root/trunk/src/game/ObjectMgr.cpp @ 111

Revision 102, 252.3 kB (checked in by yumileroy, 17 years ago)

[svn] Fixed copyright notices to comply with GPL.

Original author: w12x
Date: 2008-10-23 03:29:52-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 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 "Common.h"
22#include "Database/DatabaseEnv.h"
23#include "Database/SQLStorage.h"
24
25#include "Log.h"
26#include "MapManager.h"
27#include "ObjectMgr.h"
28#include "SpellMgr.h"
29#include "UpdateMask.h"
30#include "World.h"
31#include "WorldSession.h"
32#include "Group.h"
33#include "Guild.h"
34#include "ArenaTeam.h"
35#include "Transports.h"
36#include "ProgressBar.h"
37#include "Policies/SingletonImp.h"
38#include "Language.h"
39#include "GameEvent.h"
40#include "Spell.h"
41#include "Chat.h"
42#include "AccountMgr.h"
43#include "InstanceSaveMgr.h"
44#include "SpellAuras.h"
45#include "Util.h"
46
47INSTANTIATE_SINGLETON_1(ObjectMgr);
48
49ScriptMapMap sQuestEndScripts;
50ScriptMapMap sQuestStartScripts;
51ScriptMapMap sSpellScripts;
52ScriptMapMap sGameObjectScripts;
53ScriptMapMap sEventScripts;
54
55bool normalizePlayerName(std::string& name)
56{
57    if(name.empty())
58        return false;
59
60    wchar_t wstr_buf[MAX_INTERNAL_PLAYER_NAME+1];
61    size_t wstr_len = MAX_INTERNAL_PLAYER_NAME;
62
63    if(!Utf8toWStr(name,&wstr_buf[0],wstr_len))
64        return false;
65
66    wstr_buf[0] = wcharToUpper(wstr_buf[0]);
67    for(size_t i = 1; i < wstr_len; ++i)
68        wstr_buf[i] = wcharToLower(wstr_buf[i]);
69
70    if(!WStrToUtf8(wstr_buf,wstr_len,name))
71        return false;
72
73    return true;
74}
75
76LanguageDesc lang_description[LANGUAGES_COUNT] =
77{
78    { LANG_ADDON,           0, 0                       },
79    { LANG_UNIVERSAL,       0, 0                       },
80    { LANG_ORCISH,        669, SKILL_LANG_ORCISH       },
81    { LANG_DARNASSIAN,    671, SKILL_LANG_DARNASSIAN   },
82    { LANG_TAURAHE,       670, SKILL_LANG_TAURAHE      },
83    { LANG_DWARVISH,      672, SKILL_LANG_DWARVEN      },
84    { LANG_COMMON,        668, SKILL_LANG_COMMON       },
85    { LANG_DEMONIC,       815, SKILL_LANG_DEMON_TONGUE },
86    { LANG_TITAN,         816, SKILL_LANG_TITAN        },
87    { LANG_THALASSIAN,    813, SKILL_LANG_THALASSIAN   },
88    { LANG_DRACONIC,      814, SKILL_LANG_DRACONIC     },
89    { LANG_KALIMAG,       817, SKILL_LANG_OLD_TONGUE   },
90    { LANG_GNOMISH,      7340, SKILL_LANG_GNOMISH      },
91    { LANG_TROLL,        7341, SKILL_LANG_TROLL        },
92    { LANG_GUTTERSPEAK, 17737, SKILL_LANG_GUTTERSPEAK  },
93    { LANG_DRAENEI,     29932, SKILL_LANG_DRAENEI      },
94    { LANG_ZOMBIE,          0, 0                       },
95    { LANG_GNOMISH_BINARY,  0, 0                       },
96    { LANG_GOBLIN_BINARY,   0, 0                       }
97};
98
99LanguageDesc const* GetLanguageDescByID(uint32 lang)
100{
101    for(int i = 0; i < LANGUAGES_COUNT; ++i)
102    {
103        if(uint32(lang_description[i].lang_id) == lang)
104            return &lang_description[i];
105    }
106
107    return NULL;
108}
109
110ObjectMgr::ObjectMgr()
111{
112    m_hiCharGuid        = 1;
113    m_hiCreatureGuid    = 1;
114    m_hiPetGuid         = 1;
115    m_hiItemGuid        = 1;
116    m_hiGoGuid          = 1;
117    m_hiDoGuid          = 1;
118    m_hiCorpseGuid      = 1;
119
120    m_hiPetNumber       = 1;
121
122    mGuildBankTabPrice.resize(GUILD_BANK_MAX_TABS);
123    mGuildBankTabPrice[0] = 100;
124    mGuildBankTabPrice[1] = 250;
125    mGuildBankTabPrice[2] = 500;
126    mGuildBankTabPrice[3] = 1000;
127    mGuildBankTabPrice[4] = 2500;
128    mGuildBankTabPrice[5] = 5000;
129
130    // Only zero condition left, others will be added while loading DB tables
131    mConditions.resize(1);
132}
133
134ObjectMgr::~ObjectMgr()
135{
136    for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++ i )
137    {
138        delete i->second;
139    }
140    mQuestTemplates.clear( );
141
142    for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++ i )
143    {
144        delete i->second;
145    }
146    mGossipText.clear( );
147
148    mAreaTriggers.clear();
149
150    for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++ i )
151    {
152        delete[] i->second;
153    }
154    petInfo.clear();
155
156    // free only if loaded
157    for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
158        delete[] playerClassInfo[class_].levelInfo;
159
160    for (int race = 0; race < MAX_RACES; ++race)
161        for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
162            delete[] playerInfo[race][class_].levelInfo;
163
164    // free group and guild objects
165    for (GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr)
166        delete (*itr);
167    for (GuildSet::iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr)
168        delete (*itr);
169
170    for (CachePlayerInfoMap::iterator itr = m_mPlayerInfoMap.begin(); itr != m_mPlayerInfoMap.end(); ++itr)
171        delete itr->second;
172
173    for(ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
174        delete itr->second;
175
176    for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr)
177        itr->second.Clear();
178
179    for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr)
180        itr->second.Clear();
181}
182
183void ObjectMgr::LoadPlayerInfoInCache()
184{
185    QueryResult *result = CharacterDatabase.PQuery("SELECT guid, name, data, class  FROM characters");
186    if(!result)
187    {
188        sLog.outError( "Loading Player Cache failed.");
189        return;
190    }
191
192    PCachePlayerInfo pPPlayerInfo = NULL;
193    Field *fields = NULL;
194    Tokens tdata;
195    barGoLink bar( result->GetRowCount() );
196    do
197    {
198        bar.step();
199        fields = result->Fetch();
200        pPPlayerInfo = new CachePlayerInfo();
201
202        pPPlayerInfo->sPlayerName = fields[1].GetString();
203
204        tdata.clear();
205        tdata = StrSplit(fields[2].GetCppString(), " ");
206
207        pPPlayerInfo->unLevel = Player::GetUInt32ValueFromArray(tdata,UNIT_FIELD_LEVEL);
208        pPPlayerInfo->unfield = Player::GetUInt32ValueFromArray(tdata,UNIT_FIELD_BYTES_0);
209
210        pPPlayerInfo->unArenaInfoId0 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6);
211        pPPlayerInfo->unArenaInfoId1 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6);
212        pPPlayerInfo->unArenaInfoId2 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6);
213
214        pPPlayerInfo->unArenaInfoSlot0 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5);
215        pPPlayerInfo->unArenaInfoSlot1 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5);
216        pPPlayerInfo->unArenaInfoSlot2 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5);
217   
218        pPPlayerInfo->unClass = (uint32)fields[3].GetUInt32();
219        m_mPlayerInfoMap[fields[0].GetUInt32()] = pPPlayerInfo;
220    }
221    while (result->NextRow());
222    delete result;
223
224    sLog.outString();
225    sLog.outString( ">> Loaded info about %d players", m_mPlayerInfoMap.size());
226}
227
228PCachePlayerInfo ObjectMgr::GetPlayerInfoFromCache(uint32 unPlayerGuid) const
229{
230    //Now m_mPlayerInfoMap is using only for search, but when dinamic inserting/removing
231    //will be implemented we should lock it to prevent simultaneous access.
232    //Inserting - when new created player is saving
233    //Removing - when player has been deleted
234    CachePlayerInfoMap::const_iterator ipos = m_mPlayerInfoMap.find(unPlayerGuid);
235    return ipos == m_mPlayerInfoMap.end() ? NULL : ipos->second;
236}
237
238Group * ObjectMgr::GetGroupByLeader(const uint64 &guid) const
239{
240    for(GroupSet::const_iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr)
241        if ((*itr)->GetLeaderGUID() == guid)
242            return *itr;
243
244    return NULL;
245}
246
247Guild * ObjectMgr::GetGuildById(const uint32 GuildId) const
248{
249    for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
250        if ((*itr)->GetId() == GuildId)
251            return *itr;
252
253    return NULL;
254}
255
256Guild * ObjectMgr::GetGuildByName(std::string guildname) const
257{
258    for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
259        if ((*itr)->GetName() == guildname)
260            return *itr;
261
262    return NULL;
263}
264
265std::string ObjectMgr::GetGuildNameById(const uint32 GuildId) const
266{
267    for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
268        if ((*itr)->GetId() == GuildId)
269            return (*itr)->GetName();
270
271    return "";
272}
273
274Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const
275{
276    for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr)
277        if( (*itr)->GetLeader() == guid)
278            return *itr;
279
280    return NULL;
281}
282
283ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 ArenaTeamId) const
284{
285    for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
286        if ((*itr)->GetId() == ArenaTeamId)
287            return *itr;
288
289    return NULL;
290}
291
292ArenaTeam* ObjectMgr::GetArenaTeamByName(std::string arenateamname) const
293{
294    for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
295        if ((*itr)->GetName() == arenateamname)
296            return *itr;
297
298    return NULL;
299}
300
301ArenaTeam* ObjectMgr::GetArenaTeamByCapitan(uint64 const& guid) const
302{
303    for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
304        if ((*itr)->GetCaptain() == guid)
305            return *itr;
306
307    return NULL;
308}
309
310AuctionHouseObject * ObjectMgr::GetAuctionsMap( uint32 location )
311{
312    switch ( location )
313    {
314        case 6:                                             //horde
315            return & mHordeAuctions;
316            break;
317        case 2:                                             //alliance
318            return & mAllianceAuctions;
319            break;
320        default:                                            //neutral
321            return & mNeutralAuctions;
322    }
323}
324
325uint32 ObjectMgr::GetAuctionCut(uint32 location, uint32 highBid)
326{
327    if (location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
328        return (uint32) (0.15f * highBid * sWorld.getRate(RATE_AUCTION_CUT));
329    else
330        return (uint32) (0.05f * highBid * sWorld.getRate(RATE_AUCTION_CUT));
331}
332
333uint32 ObjectMgr::GetAuctionDeposit(uint32 location, uint32 time, Item *pItem)
334{
335    float percentance;                                      // in 0..1
336    if ( location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
337        percentance = 0.75f;
338    else
339        percentance = 0.15f;
340
341    percentance *= sWorld.getRate(RATE_AUCTION_DEPOSIT);
342
343    return uint32( percentance * pItem->GetProto()->SellPrice * pItem->GetCount() * (time / MIN_AUCTION_TIME ) );
344}
345
346/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
347uint32 ObjectMgr::GetAuctionOutBid(uint32 currentBid)
348{
349    uint32 outbid = (currentBid / 100) * 5;
350    if (!outbid)
351        outbid = 1;
352    return outbid;
353}
354
355//does not clear ram
356void ObjectMgr::SendAuctionWonMail( AuctionEntry *auction )
357{
358    Item *pItem = GetAItem(auction->item_guidlow);
359    if(!pItem)
360        return;
361
362    uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
363    Player *bidder = GetPlayer(bidder_guid);
364
365    uint32 bidder_accId = 0;
366
367    // data for gm.log
368    if( sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
369    {
370        uint32 bidder_security = 0;
371        std::string bidder_name;
372        if (bidder)
373        {
374            bidder_accId = bidder->GetSession()->GetAccountId();
375            bidder_security = bidder->GetSession()->GetSecurity();
376            bidder_name = bidder->GetName();
377        }
378        else
379        {
380            bidder_accId = GetPlayerAccountIdByGUID(bidder_guid);
381            bidder_security = accmgr.GetSecurity(bidder_accId);
382
383            if(bidder_security > SEC_PLAYER )               // not do redundant DB requests
384            {
385                if(!GetPlayerNameByGUID(bidder_guid,bidder_name))
386                    bidder_name = GetTrinityStringForDBCLocale(LANG_UNKNOWN);
387            }
388        }
389
390        if( bidder_security > SEC_PLAYER )
391        {
392            std::string owner_name;
393            if(!GetPlayerNameByGUID(auction->owner,owner_name))
394                owner_name = GetTrinityStringForDBCLocale(LANG_UNKNOWN);
395
396            uint32 owner_accid = GetPlayerAccountIdByGUID(auction->owner);
397
398            sLog.outCommand("GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)",
399                bidder_name.c_str(),bidder_accId,pItem->GetProto()->Name1,pItem->GetEntry(),pItem->GetCount(),auction->bid,owner_name.c_str(),owner_accid);
400        }
401    }
402    else if(!bidder)
403        bidder_accId = GetPlayerAccountIdByGUID(bidder_guid);
404
405    // receiver exist
406    if(bidder || bidder_accId)
407    {
408        std::ostringstream msgAuctionWonSubject;
409        msgAuctionWonSubject << auction->item_template << ":0:" << AUCTION_WON;
410
411        std::ostringstream msgAuctionWonBody;
412        msgAuctionWonBody.width(16);
413        msgAuctionWonBody << std::right << std::hex << auction->owner;
414        msgAuctionWonBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
415        sLog.outDebug( "AuctionWon body string : %s", msgAuctionWonBody.str().c_str() );
416
417        //prepare mail data... :
418        uint32 itemTextId = this->CreateItemText( msgAuctionWonBody.str() );
419
420        // set owner to bidder (to prevent delete item with sender char deleting)
421        // owner in `data` will set at mail receive and item extracting
422        CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'",auction->bidder,pItem->GetGUIDLow());
423        CharacterDatabase.CommitTransaction();
424
425        MailItemsInfo mi;
426        mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
427
428        if (bidder)
429            bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, bidder_guid, 0, 0, auction->item_template);
430        else
431            RemoveAItem(pItem->GetGUIDLow());               // we have to remove the item, before we delete it !!
432
433        // will delete item or place to receiver mail list
434        WorldSession::SendMailTo(bidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionWonSubject.str(), itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_AUCTION);
435    }
436    // receiver not exist
437    else
438    {
439        CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", pItem->GetGUIDLow());
440        RemoveAItem(pItem->GetGUIDLow());                   // we have to remove the item, before we delete it !!
441        delete pItem;
442    }
443}
444
445void ObjectMgr::SendAuctionSalePendingMail( AuctionEntry * auction )
446{
447    uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
448    Player *owner = GetPlayer(owner_guid);
449
450    // owner exist (online or offline)
451    if(owner || GetPlayerAccountIdByGUID(owner_guid))
452    {
453        std::ostringstream msgAuctionSalePendingSubject;
454        msgAuctionSalePendingSubject << auction->item_template << ":0:" << AUCTION_SALE_PENDING;
455
456        std::ostringstream msgAuctionSalePendingBody;
457        uint32 auctionCut = GetAuctionCut(auction->location, auction->bid);
458
459        time_t distrTime = time(NULL) + HOUR;
460
461        msgAuctionSalePendingBody.width(16);
462        msgAuctionSalePendingBody << std::right << std::hex << auction->bidder;
463        msgAuctionSalePendingBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
464        msgAuctionSalePendingBody << ":" << auction->deposit << ":" << auctionCut << ":0:";
465        msgAuctionSalePendingBody << secsToTimeBitFields(distrTime);
466
467        sLog.outDebug("AuctionSalePending body string : %s", msgAuctionSalePendingBody.str().c_str());
468
469        uint32 itemTextId = this->CreateItemText( msgAuctionSalePendingBody.str() );
470
471        WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSalePendingSubject.str(), itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_AUCTION);
472    }
473}
474
475//call this method to send mail to auction owner, when auction is successful, it does not clear ram
476void ObjectMgr::SendAuctionSuccessfulMail( AuctionEntry * auction )
477{
478    uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
479    Player *owner = GetPlayer(owner_guid);
480
481    uint32 owner_accId = 0;
482    if(!owner)
483        owner_accId = GetPlayerAccountIdByGUID(owner_guid);
484
485    // owner exist
486    if(owner || owner_accId)
487    {
488        std::ostringstream msgAuctionSuccessfulSubject;
489        msgAuctionSuccessfulSubject << auction->item_template << ":0:" << AUCTION_SUCCESSFUL;
490
491        std::ostringstream auctionSuccessfulBody;
492        uint32 auctionCut = GetAuctionCut(auction->location, auction->bid);
493
494        auctionSuccessfulBody.width(16);
495        auctionSuccessfulBody << std::right << std::hex << auction->bidder;
496        auctionSuccessfulBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
497        auctionSuccessfulBody << ":" << auction->deposit << ":" << auctionCut;
498
499        sLog.outDebug("AuctionSuccessful body string : %s", auctionSuccessfulBody.str().c_str());
500
501        uint32 itemTextId = this->CreateItemText( auctionSuccessfulBody.str() );
502
503        uint32 profit = auction->bid + auction->deposit - auctionCut;
504
505        if (owner)
506        {
507            //send auction owner notification, bidder must be current!
508            owner->GetSession()->SendAuctionOwnerNotification( auction );
509        }
510
511        WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSuccessfulSubject.str(), itemTextId, NULL, profit, 0, MAIL_CHECK_MASK_AUCTION, HOUR);
512    }
513}
514
515//does not clear ram
516void ObjectMgr::SendAuctionExpiredMail( AuctionEntry * auction )
517{                                                           //return an item in auction to its owner by mail
518    Item *pItem = GetAItem(auction->item_guidlow);
519    if(!pItem)
520    {
521        sLog.outError("Auction item (GUID: %u) not found, and lost.",auction->item_guidlow);
522        return;
523    }
524
525    uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
526    Player *owner = GetPlayer(owner_guid);
527
528    uint32 owner_accId = 0;
529    if(!owner)
530        owner_accId = GetPlayerAccountIdByGUID(owner_guid);
531
532    // owner exist
533    if(owner || owner_accId)
534    {
535        std::ostringstream subject;
536        subject << auction->item_template << ":0:" << AUCTION_EXPIRED;
537
538        if ( owner )
539            owner->GetSession()->SendAuctionOwnerNotification( auction );
540        else
541            RemoveAItem(pItem->GetGUIDLow());               // we have to remove the item, before we delete it !!
542
543        MailItemsInfo mi;
544        mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
545
546        // will delete item or place to receiver mail list
547        WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, GUID_LOPART(owner_guid), subject.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
548
549    }
550    // owner not found
551    else
552    {
553        CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'",pItem->GetGUIDLow());
554        RemoveAItem(pItem->GetGUIDLow());                   // we have to remove the item, before we delete it !!
555        delete pItem;
556    }
557}
558
559CreatureInfo const* ObjectMgr::GetCreatureTemplate(uint32 id)
560{
561    return sCreatureStorage.LookupEntry<CreatureInfo>(id);
562}
563
564void ObjectMgr::LoadCreatureLocales()
565{
566    mCreatureLocaleMap.clear();
567   
568    QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,subname_loc1,name_loc2,subname_loc2,name_loc3,subname_loc3,name_loc4,subname_loc4,name_loc5,subname_loc5,name_loc6,subname_loc6,name_loc7,subname_loc7,name_loc8,subname_loc8 FROM locales_creature");
569
570    if(!result)
571    {
572        barGoLink bar(1);
573
574        bar.step();
575
576        sLog.outString("");
577        sLog.outString(">> Loaded 0 creature locale strings. DB table `locales_creature` is empty.");
578        return;
579    }
580
581    barGoLink bar(result->GetRowCount());
582
583    do
584    {
585        Field *fields = result->Fetch();
586        bar.step();
587
588        uint32 entry = fields[0].GetUInt32();
589
590        CreatureLocale& data = mCreatureLocaleMap[entry];
591
592        for(int i = 1; i < MAX_LOCALE; ++i)
593        {
594            std::string str = fields[1+2*(i-1)].GetCppString();
595            if(!str.empty())
596            {
597                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
598                if(idx >= 0)
599                {
600                    if(data.Name.size() <= idx)
601                        data.Name.resize(idx+1);
602
603                    data.Name[idx] = str;
604                }
605            }
606            str = fields[1+2*(i-1)+1].GetCppString();
607            if(!str.empty())
608            {
609                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
610                if(idx >= 0)
611                {
612                    if(data.SubName.size() <= idx)
613                        data.SubName.resize(idx+1);
614
615                    data.SubName[idx] = str;
616                }
617            }
618        }
619    } while (result->NextRow());
620
621    delete result;
622
623    sLog.outString();
624    sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() );
625}
626
627void ObjectMgr::LoadCreatureTemplates()
628{
629    sCreatureStorage.Load();
630
631    sLog.outString( ">> Loaded %u creature definitions", sCreatureStorage.RecordCount );
632    sLog.outString();
633
634    std::set<uint32> heroicEntries;                         // already loaded heroic value in creatures
635    std::set<uint32> hasHeroicEntries;                      // already loaded creatures with heroic entry values
636
637    // check data correctness
638    for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
639    {
640        CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i);
641        if(!cInfo)
642            continue;
643
644        if(cInfo->HeroicEntry)
645        {
646            CreatureInfo const* heroicInfo = GetCreatureTemplate(cInfo->HeroicEntry);
647            if(!heroicInfo)
648            {
649                sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u not exist.",cInfo->HeroicEntry,cInfo->HeroicEntry);
650                continue;
651            }
652
653            if(heroicEntries.find(i)!=heroicEntries.end())
654            {
655                sLog.outErrorDb("Creature (Entry: %u) listed as heroic but have value in `heroic_entry`.",i);
656                continue;
657            }
658
659            if(heroicEntries.find(cInfo->HeroicEntry)!=heroicEntries.end())
660            {
661                sLog.outErrorDb("Creature (Entry: %u) already listed as heroic for another entry.",cInfo->HeroicEntry);
662                continue;
663            }
664
665            if(hasHeroicEntries.find(cInfo->HeroicEntry)!=hasHeroicEntries.end())
666            {
667                sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u have heroic entry also.",i,cInfo->HeroicEntry,cInfo->HeroicEntry);
668                continue;
669            }
670
671            if(cInfo->npcflag != heroicInfo->npcflag)
672            {
673                sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `npcflag` in heroic mode.",i);
674                continue;
675            }
676
677            if(cInfo->classNum != heroicInfo->classNum)
678            {
679                sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `classNum` in heroic mode.",i);
680                continue;
681            }
682
683            if(cInfo->race != heroicInfo->race)
684            {
685                sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `race` in heroic mode.",i);
686                continue;
687            }
688
689            if(cInfo->trainer_type != heroicInfo->trainer_type)
690            {
691                sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_type` in heroic mode.",i);
692                continue;
693            }
694
695            if(cInfo->trainer_spell != heroicInfo->trainer_spell)
696            {
697                sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_spell` in heroic mode.",i);
698                continue;
699            }
700
701            hasHeroicEntries.insert(i);
702            heroicEntries.insert(cInfo->HeroicEntry);
703        }
704
705        FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A);
706        if(!factionTemplate)
707            sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A);
708
709        factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H);
710        if(!factionTemplate)
711            sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H);
712
713        CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->DisplayID_A);
714        if (!minfo)
715            sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_A (%u)", cInfo->Entry, cInfo->DisplayID_A);
716        minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->DisplayID_H);
717        if (!minfo)
718            sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_H (%u)", cInfo->Entry, cInfo->DisplayID_H);
719
720        if(cInfo->dmgschool >= MAX_SPELL_SCHOOL)
721        {
722            sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool);
723            const_cast<CreatureInfo*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
724        }
725
726        if(cInfo->baseattacktime == 0)
727            const_cast<CreatureInfo*>(cInfo)->baseattacktime  = BASE_ATTACK_TIME;
728
729        if(cInfo->rangeattacktime == 0)
730            const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
731
732        if((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
733            sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type);
734
735        if(cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
736        {
737            sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType);
738            const_cast<CreatureInfo*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
739        }
740
741        if(cInfo->PetSpellDataId)
742        {
743            CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
744            if(!spellDataId)
745                sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId);
746        }
747
748        if(cInfo->MovementType >= MAX_DB_MOTION_TYPE)
749        {
750            sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType);
751            const_cast<CreatureInfo*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
752        }
753
754        if(cInfo->equipmentId > 0)                          // 0 no equipment
755        {
756            if(!GetEquipmentInfo(cInfo->equipmentId))
757            {
758                sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId);
759                const_cast<CreatureInfo*>(cInfo)->equipmentId = 0;
760            }
761        }
762
763        /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc
764        if(cInfo->scale <= 0.0f)
765        {
766            CreatureDisplayInfoEntry const* ScaleEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->DisplayID_A);
767            const_cast<CreatureInfo*>(cInfo)->scale = ScaleEntry ? ScaleEntry->scale : 1.0f;
768        }
769    }
770}
771
772void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr)
773{
774    // Now add the auras, format "spellid effectindex spellid effectindex..."
775    char *p,*s;
776    std::vector<int> val;
777    s=p=(char*)reinterpret_cast<char const*>(addon->auras);
778    if(p)
779    {
780        while (p[0]!=0)
781        {
782            ++p;
783            if (p[0]==' ')
784            {
785                val.push_back(atoi(s));
786                s=++p;
787            }
788        }
789        if (p!=s)
790            val.push_back(atoi(s));
791
792        // free char* loaded memory
793        delete[] (char*)reinterpret_cast<char const*>(addon->auras);
794
795        // wrong list
796        if (val.size()%2)
797        {
798            addon->auras = NULL;
799            sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`.",guidEntryStr,addon->guidOrEntry,table);
800            return;
801        }
802    }
803
804    // empty list
805    if(val.empty())
806    {
807        addon->auras = NULL;
808        return;
809    }
810
811    // replace by new strucutres array
812    const_cast<CreatureDataAddonAura*&>(addon->auras) = new CreatureDataAddonAura[val.size()/2+1];
813
814    int i=0;
815    for(int j=0;j<val.size()/2;++j)
816    {
817        CreatureDataAddonAura& cAura = const_cast<CreatureDataAddonAura&>(addon->auras[i]);
818        cAura.spell_id = (uint32)val[2*j+0];
819        cAura.effect_idx  = (uint32)val[2*j+1];
820        if ( cAura.effect_idx > 2 )
821        {
822            sLog.outErrorDb("Creature (%s: %u) has wrong effect %u for spell %u in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table);
823            continue;
824        }
825        SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura.spell_id);
826        if (!AdditionalSpellInfo)
827        {
828            sLog.outErrorDb("Creature (%s: %u) has wrong spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table);
829            continue;
830        }
831
832        if (!AdditionalSpellInfo->Effect[cAura.effect_idx] || !AdditionalSpellInfo->EffectApplyAuraName[cAura.effect_idx])
833        {
834            sLog.outErrorDb("Creature (%s: %u) has not aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table);
835            continue;
836        }
837
838        ++i;
839    }
840
841    // fill terminator element (after last added)
842    CreatureDataAddonAura& endAura = const_cast<CreatureDataAddonAura&>(addon->auras[i]);
843    endAura.spell_id   = 0;
844    endAura.effect_idx = 0;
845}
846
847void ObjectMgr::LoadCreatureAddons()
848{
849    sCreatureInfoAddonStorage.Load();
850
851    sLog.outString( ">> Loaded %u creature template addons", sCreatureInfoAddonStorage.RecordCount );
852    sLog.outString();
853
854    // check data correctness and convert 'auras'
855    for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i)
856    {
857        CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i);
858        if(!addon)
859            continue;
860
861        ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_template_addon", "Entry");
862
863        if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry))
864            sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `creature_template_addon`",addon->guidOrEntry);
865    }
866
867    sCreatureDataAddonStorage.Load();
868
869    sLog.outString( ">> Loaded %u creature addons", sCreatureDataAddonStorage.RecordCount );
870    sLog.outString();
871
872    // check data correctness and convert 'auras'
873    for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i)
874    {
875        CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i);
876        if(!addon)
877            continue;
878
879        ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_addon", "GUIDLow");
880
881        if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end())
882            sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry);
883    }
884}
885
886EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry)
887{
888    return sEquipmentStorage.LookupEntry<EquipmentInfo>(entry);
889}
890
891void ObjectMgr::LoadEquipmentTemplates()
892{
893    sEquipmentStorage.Load();
894
895    sLog.outString( ">> Loaded %u equipment template", sEquipmentStorage.RecordCount );
896    sLog.outString();
897}
898
899CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid)
900{
901    return sCreatureModelStorage.LookupEntry<CreatureModelInfo>(modelid);
902}
903
904uint32 ObjectMgr::ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data)
905{
906    // Load creature model (display id)
907    uint32 display_id;
908    if (!data || data->displayid == 0)                      // use defaults from the template
909    {
910        // DisplayID_A is used if no team is given
911        if (team == HORDE)
912            display_id = (cinfo->DisplayID_H2 != 0 && urand(0,1) == 0) ? cinfo->DisplayID_H2 : cinfo->DisplayID_H;
913        else
914            display_id = (cinfo->DisplayID_A2 != 0 && urand(0,1) == 0) ? cinfo->DisplayID_A2 : cinfo->DisplayID_A;
915    }
916    else                                                    // overriden in creature data
917        display_id = data->displayid;
918
919    return display_id;
920}
921
922CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_id)
923{
924    CreatureModelInfo const *minfo = GetCreatureModelInfo(display_id);
925    if(!minfo)
926        return NULL;
927
928    // If a model for another gender exists, 50% chance to use it
929    if(minfo->modelid_other_gender != 0 && urand(0,1) == 0)
930    {
931        CreatureModelInfo const *minfo_tmp = GetCreatureModelInfo(minfo->modelid_other_gender);
932        if(!minfo_tmp)
933        {
934            sLog.outErrorDb("Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", minfo->modelid, minfo->modelid_other_gender);
935            return minfo;                                   // not fatal, just use the previous one
936        }
937        else
938            return minfo_tmp;
939    }
940    else
941        return minfo;
942}
943
944void ObjectMgr::LoadCreatureModelInfo()
945{
946    sCreatureModelStorage.Load();
947
948    sLog.outString( ">> Loaded %u creature model based info", sCreatureModelStorage.RecordCount );
949    sLog.outString();
950}
951
952void ObjectMgr::LoadCreatures()
953{
954    uint32 count = 0;
955    //                                                0              1   2    3
956    QueryResult *result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid,"
957    //   4             5           6           7           8            9              10         11
958        "equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint,"
959    //   12         13       14          15            16         17
960        "curhealth, curmana, DeathState, MovementType, spawnMask, event "
961        "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid");
962
963    if(!result)
964    {
965        barGoLink bar(1);
966
967        bar.step();
968
969        sLog.outString("");
970        sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty.");
971        return;
972    }
973
974    // build single time for check creature data
975    std::set<uint32> heroicCreatures;
976    for(uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i)
977        if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
978            if(cInfo->HeroicEntry)
979                heroicCreatures.insert(cInfo->HeroicEntry);
980
981    barGoLink bar(result->GetRowCount());
982
983    do
984    {
985        Field *fields = result->Fetch();
986        bar.step();
987
988        uint32 guid = fields[0].GetUInt32();
989
990        CreatureData& data = mCreatureDataMap[guid];
991
992        data.id             = fields[ 1].GetUInt32();
993        data.mapid          = fields[ 2].GetUInt32();
994        data.displayid      = fields[ 3].GetUInt32();
995        data.equipmentId    = fields[ 4].GetUInt32();
996        data.posX           = fields[ 5].GetFloat();
997        data.posY           = fields[ 6].GetFloat();
998        data.posZ           = fields[ 7].GetFloat();
999        data.orientation    = fields[ 8].GetFloat();
1000        data.spawntimesecs  = fields[ 9].GetUInt32();
1001        data.spawndist      = fields[10].GetFloat();
1002        data.currentwaypoint= fields[11].GetUInt32();
1003        data.curhealth      = fields[12].GetUInt32();
1004        data.curmana        = fields[13].GetUInt32();
1005        data.is_dead        = fields[14].GetBool();
1006        data.movementType   = fields[15].GetUInt8();
1007        data.spawnMask      = fields[16].GetUInt8();
1008        int16 gameEvent     = fields[17].GetInt16();
1009
1010        CreatureInfo const* cInfo = GetCreatureTemplate(data.id);
1011        if(!cInfo)
1012        {
1013            sLog.outErrorDb("Table `creature` have creature (GUID: %u) with not existed creature entry %u, skipped.",guid,data.id );
1014            continue;
1015        }
1016
1017        if(heroicCreatures.find(data.id)!=heroicCreatures.end())
1018        {
1019            sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template in `creature_template_substitution`, skipped.",guid,data.id );
1020            continue;
1021        }
1022
1023        if(data.equipmentId > 0)                            // -1 no equipment, 0 use default
1024        {
1025            if(!GetEquipmentInfo(data.equipmentId))
1026            {
1027                sLog.outErrorDb("Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId);
1028                data.equipmentId = -1;
1029            }
1030        }
1031
1032        if(cInfo->RegenHealth && data.curhealth < cInfo->minhealth)
1033        {
1034            sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.",guid,data.id,data.curhealth, cInfo->minhealth );
1035            data.curhealth = cInfo->minhealth;
1036        }
1037
1038        if(data.curmana < cInfo->minmana)
1039        {
1040            sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana );
1041            data.curmana = cInfo->minmana;
1042        }
1043
1044        if(data.spawndist < 0.0f)
1045        {
1046            sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.",guid,data.id );
1047            data.spawndist = 0.0f;
1048        }
1049        else if(data.movementType == RANDOM_MOTION_TYPE)
1050        {
1051            if(data.spawndist == 0.0f)
1052            {
1053                sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=1 (random movement) but with `spawndist`=0, replace by idle movement type (0).",guid,data.id );
1054                data.movementType = IDLE_MOTION_TYPE;
1055            }
1056        }
1057        else if(data.movementType == IDLE_MOTION_TYPE)
1058        {
1059            if(data.spawndist != 0.0f)
1060            {
1061                sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=0 (idle) have `spawndist`<>0, set to 0.",guid,data.id );
1062                data.spawndist = 0.0f;
1063            }
1064        }
1065
1066        if (gameEvent==0)                                   // if not this is to be managed by GameEvent System
1067            AddCreatureToGrid(guid, &data);
1068        ++count;
1069
1070    } while (result->NextRow());
1071
1072    delete result;
1073
1074    sLog.outString();
1075    sLog.outString( ">> Loaded %u creatures", mCreatureDataMap.size() );
1076}
1077
1078void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data)
1079{
1080    uint8 mask = data->spawnMask;
1081    for(uint8 i = 0; mask != 0; i++, mask >>= 1)
1082    {
1083        if(mask & 1)
1084        {
1085            CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
1086            uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
1087
1088            CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
1089            cell_guids.creatures.insert(guid);
1090        }
1091    }
1092}
1093
1094void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data)
1095{
1096    uint8 mask = data->spawnMask;
1097    for(uint8 i = 0; mask != 0; i++, mask >>= 1)
1098    {
1099        if(mask & 1)
1100        {
1101            CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
1102            uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
1103
1104            CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
1105            cell_guids.creatures.erase(guid);
1106        }
1107    }
1108}
1109
1110void ObjectMgr::LoadGameobjects()
1111{
1112    uint32 count = 0;
1113
1114    //                                                0                1   2    3           4           5           6
1115    QueryResult *result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation,"
1116    //   7          8          9          10         11             12            13     14         15
1117        "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, event "
1118        "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid");
1119
1120    if(!result)
1121    {
1122        barGoLink bar(1);
1123
1124        bar.step();
1125
1126        sLog.outString();
1127        sLog.outErrorDb(">> Loaded 0 gameobjects. DB table `gameobject` is empty.");
1128        return;
1129    }
1130
1131    barGoLink bar(result->GetRowCount());
1132
1133    do
1134    {
1135        Field *fields = result->Fetch();
1136        bar.step();
1137
1138        uint32 guid = fields[0].GetUInt32();
1139
1140        GameObjectData& data = mGameObjectDataMap[guid];
1141
1142        data.id             = fields[ 1].GetUInt32();
1143        data.mapid          = fields[ 2].GetUInt32();
1144        data.posX           = fields[ 3].GetFloat();
1145        data.posY           = fields[ 4].GetFloat();
1146        data.posZ           = fields[ 5].GetFloat();
1147        data.orientation    = fields[ 6].GetFloat();
1148        data.rotation0      = fields[ 7].GetFloat();
1149        data.rotation1      = fields[ 8].GetFloat();
1150        data.rotation2      = fields[ 9].GetFloat();
1151        data.rotation3      = fields[10].GetFloat();
1152        data.spawntimesecs  = fields[11].GetInt32();
1153        data.animprogress   = fields[12].GetUInt32();
1154        data.go_state       = fields[13].GetUInt32();
1155        data.ArtKit         = 0;
1156        data.spawnMask      = fields[14].GetUInt8();
1157        int16 gameEvent     = fields[15].GetInt16();
1158
1159        GameObjectInfo const* gInfo = GetGameObjectInfo(data.id);
1160        if(!gInfo)
1161        {
1162            sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u) with not existed gameobject entry %u, skipped.",guid,data.id );
1163            continue;
1164        }
1165
1166        if (gameEvent==0)                                   // if not this is to be managed by GameEvent System
1167            AddGameobjectToGrid(guid, &data);
1168        ++count;
1169
1170    } while (result->NextRow());
1171
1172    delete result;
1173
1174    sLog.outString();
1175    sLog.outString( ">> Loaded %u gameobjects", mGameObjectDataMap.size());
1176}
1177
1178void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data)
1179{
1180    uint8 mask = data->spawnMask;
1181    for(uint8 i = 0; mask != 0; i++, mask >>= 1)
1182    {
1183        if(mask & 1)
1184        {
1185            CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
1186            uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
1187
1188            CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
1189            cell_guids.gameobjects.insert(guid);
1190        }
1191    }
1192}
1193
1194void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data)
1195{
1196    uint8 mask = data->spawnMask;
1197    for(uint8 i = 0; mask != 0; i++, mask >>= 1)
1198    {
1199        if(mask & 1)
1200        {
1201            CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
1202            uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
1203
1204            CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
1205            cell_guids.gameobjects.erase(guid);
1206        }
1207    }
1208}
1209
1210void ObjectMgr::LoadCreatureRespawnTimes()
1211{
1212    // remove outdated data
1213    WorldDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
1214
1215    uint32 count = 0;
1216
1217    QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM creature_respawn");
1218
1219    if(!result)
1220    {
1221        barGoLink bar(1);
1222
1223        bar.step();
1224
1225        sLog.outString();
1226        sLog.outString(">> Loaded 0 creature respawn time.");
1227        return;
1228    }
1229
1230    barGoLink bar(result->GetRowCount());
1231
1232    do
1233    {
1234        Field *fields = result->Fetch();
1235        bar.step();
1236
1237        uint32 loguid       = fields[0].GetUInt32();
1238        uint64 respawn_time = fields[1].GetUInt64();
1239        uint32 instance     = fields[2].GetUInt32();
1240
1241        mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time);
1242
1243        ++count;
1244    } while (result->NextRow());
1245
1246    delete result;
1247
1248    sLog.outString( ">> Loaded %u creature respawn times", mCreatureRespawnTimes.size() );
1249    sLog.outString();
1250}
1251
1252void ObjectMgr::LoadGameobjectRespawnTimes()
1253{
1254    // remove outdated data
1255    WorldDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
1256
1257    uint32 count = 0;
1258
1259    QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM gameobject_respawn");
1260
1261    if(!result)
1262    {
1263        barGoLink bar(1);
1264
1265        bar.step();
1266
1267        sLog.outString();
1268        sLog.outString(">> Loaded 0 gameobject respawn time.");
1269        return;
1270    }
1271
1272    barGoLink bar(result->GetRowCount());
1273
1274    do
1275    {
1276        Field *fields = result->Fetch();
1277        bar.step();
1278
1279        uint32 loguid       = fields[0].GetUInt32();
1280        uint64 respawn_time = fields[1].GetUInt64();
1281        uint32 instance     = fields[2].GetUInt32();
1282
1283        mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time);
1284
1285        ++count;
1286    } while (result->NextRow());
1287
1288    delete result;
1289
1290    sLog.outString( ">> Loaded %u gameobject respawn times", mGORespawnTimes.size() );
1291    sLog.outString();
1292}
1293
1294// name must be checked to correctness (if received) before call this function
1295uint64 ObjectMgr::GetPlayerGUIDByName(std::string name) const
1296{
1297    uint64 guid = 0;
1298
1299    CharacterDatabase.escape_string(name);
1300
1301    // Player name safe to sending to DB (checked at login) and this function using
1302    QueryResult *result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE name = '%s'", name.c_str());
1303    if(result)
1304    {
1305        guid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
1306
1307        delete result;
1308    }
1309
1310    return guid;
1311}
1312
1313bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const
1314{
1315    // prevent DB access for online player
1316    if(Player* player = GetPlayer(guid))
1317    {
1318        name = player->GetName();
1319        return true;
1320    }
1321
1322    PCachePlayerInfo pInfo = GetPlayerInfoFromCache(GUID_LOPART(guid));
1323    if(pInfo)
1324    {
1325        name = pInfo->sPlayerName.c_str();
1326        return true;
1327    }
1328
1329    QueryResult *result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
1330
1331    if(result)
1332    {
1333        name = (*result)[0].GetCppString();
1334        delete result;
1335        return true;
1336    }
1337
1338    return false;
1339}
1340
1341uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const
1342{
1343    QueryResult *result = CharacterDatabase.PQuery("SELECT race FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
1344
1345    if(result)
1346    {
1347        uint8 race = (*result)[0].GetUInt8();
1348        delete result;
1349        return Player::TeamForRace(race);
1350    }
1351
1352    return 0;
1353}
1354
1355uint32 ObjectMgr::GetPlayerAccountIdByGUID(const uint64 &guid) const
1356{
1357    QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
1358    if(result)
1359    {
1360        uint32 acc = (*result)[0].GetUInt32();
1361        delete result;
1362        return acc;
1363    }
1364
1365    return 0;
1366}
1367
1368uint32 ObjectMgr::GetPlayerAccountIdByPlayerName(std::string name) const
1369{
1370    QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'", name.c_str());
1371    if(result)
1372    {
1373        uint32 acc = (*result)[0].GetUInt32();
1374        delete result;
1375        return acc;
1376    }
1377
1378    return 0;
1379}
1380
1381void ObjectMgr::LoadAuctions()
1382{
1383    QueryResult *result = CharacterDatabase.Query("SELECT COUNT(*) FROM auctionhouse");
1384    if( !result )
1385        return;
1386
1387    Field *fields = result->Fetch();
1388    uint32 AuctionCount=fields[0].GetUInt32();
1389    delete result;
1390
1391    if(!AuctionCount)
1392        return;
1393
1394    result = CharacterDatabase.Query( "SELECT id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit,location FROM auctionhouse" );
1395    if( !result )
1396        return;
1397
1398    barGoLink bar( AuctionCount );
1399
1400    AuctionEntry *aItem;
1401
1402    do
1403    {
1404        fields = result->Fetch();
1405
1406        bar.step();
1407
1408        aItem = new AuctionEntry;
1409        aItem->Id = fields[0].GetUInt32();
1410        aItem->auctioneer = fields[1].GetUInt32();
1411        aItem->item_guidlow = fields[2].GetUInt32();
1412        aItem->item_template = fields[3].GetUInt32();
1413        aItem->owner = fields[4].GetUInt32();
1414        aItem->buyout = fields[5].GetUInt32();
1415        aItem->time = fields[6].GetUInt32();
1416        aItem->bidder = fields[7].GetUInt32();
1417        aItem->bid = fields[8].GetUInt32();
1418        aItem->startbid = fields[9].GetUInt32();
1419        aItem->deposit = fields[10].GetUInt32();
1420        aItem->location = fields[11].GetUInt8();
1421        //check if sold item exists
1422        if ( this->GetAItem( aItem->item_guidlow ) )
1423        {
1424            GetAuctionsMap( aItem->location )->AddAuction(aItem);
1425        }
1426        else
1427        {
1428            CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",aItem->Id);
1429            sLog.outError("Auction %u has not a existing item : %u", aItem->Id, aItem->item_guidlow);
1430            delete aItem;
1431        }
1432    } while (result->NextRow());
1433    delete result;
1434
1435    sLog.outString();
1436    sLog.outString( ">> Loaded %u auctions", AuctionCount );
1437    sLog.outString();
1438}
1439
1440void ObjectMgr::LoadItemLocales()
1441{
1442    mItemLocaleMap.clear();
1443   
1444    QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,description_loc1,name_loc2,description_loc2,name_loc3,description_loc3,name_loc4,description_loc4,name_loc5,description_loc5,name_loc6,description_loc6,name_loc7,description_loc7,name_loc8,description_loc8 FROM locales_item");
1445
1446    if(!result)
1447    {
1448        barGoLink bar(1);
1449
1450        bar.step();
1451
1452        sLog.outString("");
1453        sLog.outString(">> Loaded 0 Item locale strings. DB table `locales_item` is empty.");
1454        return;
1455    }
1456
1457    barGoLink bar(result->GetRowCount());
1458
1459    do
1460    {
1461        Field *fields = result->Fetch();
1462        bar.step();
1463
1464        uint32 entry = fields[0].GetUInt32();
1465
1466        ItemLocale& data = mItemLocaleMap[entry];
1467
1468        for(int i = 1; i < MAX_LOCALE; ++i)
1469        {
1470            std::string str = fields[1+2*(i-1)].GetCppString();
1471            if(!str.empty())
1472            {
1473                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
1474                if(idx >= 0)
1475                {
1476                    if(data.Name.size() <= idx)
1477                        data.Name.resize(idx+1);
1478
1479                    data.Name[idx] = str;
1480                }
1481            }
1482
1483            str = fields[1+2*(i-1)+1].GetCppString();
1484            if(!str.empty())
1485            {
1486                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
1487                if(idx >= 0)
1488                {
1489                    if(data.Description.size() <= idx)
1490                        data.Description.resize(idx+1);
1491
1492                    data.Description[idx] = str;
1493                }
1494            }
1495        }
1496    } while (result->NextRow());
1497
1498    delete result;
1499
1500    sLog.outString();
1501    sLog.outString( ">> Loaded %u Item locale strings", mItemLocaleMap.size() );
1502}
1503
1504void ObjectMgr::LoadItemPrototypes()
1505{
1506    sItemStorage.Load ();
1507    sLog.outString( ">> Loaded %u item prototypes", sItemStorage.RecordCount );
1508    sLog.outString();
1509
1510    // check data correctness
1511    for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
1512    {
1513        ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype >(i);
1514        ItemEntry const *dbcitem = sItemStore.LookupEntry(i);
1515        if(!proto)
1516        {
1517            /* to many errors, and possible not all items really used in game
1518            if (dbcitem)
1519                sLog.outErrorDb("Item (Entry: %u) doesn't exists in DB, but must exist.",i);
1520            */
1521            continue;
1522        }
1523
1524        if(dbcitem)
1525        {
1526            if(proto->InventoryType != dbcitem->InventoryType)
1527            {
1528                sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType);
1529                // It safe let use InventoryType from DB
1530            }
1531
1532            if(proto->DisplayInfoID != dbcitem->DisplayId)
1533            {
1534                sLog.outErrorDb("Item (Entry: %u) not correct %u display id, must be %u (using it).",i,proto->DisplayInfoID,dbcitem->DisplayId);
1535                const_cast<ItemPrototype*>(proto)->DisplayInfoID = dbcitem->DisplayId;
1536            }
1537            if(proto->Sheath != dbcitem->Sheath)
1538            {
1539                sLog.outErrorDb("Item (Entry: %u) not correct %u sheath, must be %u  (using it).",i,proto->Sheath,dbcitem->Sheath);
1540                const_cast<ItemPrototype*>(proto)->Sheath = dbcitem->Sheath;
1541            }
1542        }
1543        else
1544        {
1545            sLog.outErrorDb("Item (Entry: %u) not correct (not listed in list of existed items).",i);
1546        }
1547
1548        if(proto->Class >= MAX_ITEM_CLASS)
1549        {
1550            sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class);
1551            const_cast<ItemPrototype*>(proto)->Class = ITEM_CLASS_JUNK;
1552        }
1553
1554        if(proto->SubClass >= MaxItemSubclassValues[proto->Class])
1555        {
1556            sLog.outErrorDb("Item (Entry: %u) has wrong Subclass value (%u) for class %u",i,proto->SubClass,proto->Class);
1557            const_cast<ItemPrototype*>(proto)->SubClass = 0;// exist for all item classes
1558        }
1559
1560        if(proto->Quality >= MAX_ITEM_QUALITY)
1561        {
1562            sLog.outErrorDb("Item (Entry: %u) has wrong Quality value (%u)",i,proto->Quality);
1563            const_cast<ItemPrototype*>(proto)->Quality = ITEM_QUALITY_NORMAL;
1564        }
1565
1566        if(proto->BuyCount <= 0)
1567        {
1568            sLog.outErrorDb("Item (Entry: %u) has wrong BuyCount value (%u), set to default(1).",i,proto->BuyCount);
1569            const_cast<ItemPrototype*>(proto)->BuyCount = 1;
1570        }
1571
1572        if(proto->InventoryType >= MAX_INVTYPE)
1573        {
1574            sLog.outErrorDb("Item (Entry: %u) has wrong InventoryType value (%u)",i,proto->InventoryType);
1575            const_cast<ItemPrototype*>(proto)->InventoryType = INVTYPE_NON_EQUIP;
1576        }
1577
1578        if(proto->RequiredSkill >= MAX_SKILL_TYPE)
1579        {
1580            sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill);
1581            const_cast<ItemPrototype*>(proto)->RequiredSkill = 0;
1582        }
1583
1584        if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE))
1585        {
1586            sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped.",i,proto->AllowableClass);
1587        }
1588
1589        if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE))
1590        {
1591            sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped.",i,proto->AllowableRace);
1592        }
1593
1594        if(proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell))
1595        {
1596            sLog.outErrorDb("Item (Entry: %u) have wrong (non-existed) spell in RequiredSpell (%u)",i,proto->RequiredSpell);
1597            const_cast<ItemPrototype*>(proto)->RequiredSpell = 0;
1598        }
1599
1600        if(proto->RequiredReputationRank >= MAX_REPUTATION_RANK)
1601            sLog.outErrorDb("Item (Entry: %u) has wrong reputation rank in RequiredReputationRank (%u), item can't be used.",i,proto->RequiredReputationRank);
1602
1603        if(proto->RequiredReputationFaction)
1604        {
1605            if(!sFactionStore.LookupEntry(proto->RequiredReputationFaction))
1606            {
1607                sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) faction in RequiredReputationFaction (%u)",i,proto->RequiredReputationFaction);
1608                const_cast<ItemPrototype*>(proto)->RequiredReputationFaction = 0;
1609            }
1610
1611            if(proto->RequiredReputationRank == MIN_REPUTATION_RANK)
1612                sLog.outErrorDb("Item (Entry: %u) has min. reputation rank in RequiredReputationRank (0) but RequiredReputationFaction > 0, faction setting is useless.",i);
1613        }
1614        else if(proto->RequiredReputationRank > MIN_REPUTATION_RANK)
1615            sLog.outErrorDb("Item (Entry: %u) has RequiredReputationFaction ==0 but RequiredReputationRank > 0, rank setting is useless.",i);
1616
1617        if(proto->Stackable==0)
1618        {
1619            sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%u), replace by default 1.",i,proto->Stackable);
1620            const_cast<ItemPrototype*>(proto)->Stackable = 1;
1621        }
1622        else if(proto->Stackable > 255)
1623        {
1624            sLog.outErrorDb("Item (Entry: %u) has too large value in stackable (%u), replace by hardcoded upper limit (255).",i,proto->Stackable);
1625            const_cast<ItemPrototype*>(proto)->Stackable = 255;
1626        }
1627
1628        for (int j = 0; j < 10; j++)
1629        {
1630            // for ItemStatValue != 0
1631            if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD)
1632            {
1633                sLog.outErrorDb("Item (Entry: %u) has wrong stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType);
1634                const_cast<ItemPrototype*>(proto)->ItemStat[j].ItemStatType = 0;
1635            }
1636        }
1637
1638        for (int j = 0; j < 5; j++)
1639        {
1640            if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL)
1641            {
1642                sLog.outErrorDb("Item (Entry: %u) has wrong dmg_type%d (%u)",i,j+1,proto->Damage[j].DamageType);
1643                const_cast<ItemPrototype*>(proto)->Damage[j].DamageType = 0;
1644            }
1645        }
1646
1647        // special format
1648        if(proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN)
1649        {
1650            // spell_1
1651            if(proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
1652            {
1653                sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format",i,0+1,proto->Spells[0].SpellTrigger);
1654                const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
1655                const_cast<ItemPrototype*>(proto)->Spells[0].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
1656                const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
1657                const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
1658            }
1659
1660            // spell_2 have learning spell
1661            if(proto->Spells[1].SpellTrigger != ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
1662            {
1663                sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format.",i,1+1,proto->Spells[1].SpellTrigger);
1664                const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
1665                const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
1666                const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
1667            }
1668            else if(!proto->Spells[1].SpellId)
1669            {
1670                sLog.outErrorDb("Item (Entry: %u) not has expected spell in spellid_%d in special learning format.",i,1+1);
1671                const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
1672                const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
1673            }
1674            else
1675            {
1676                SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[1].SpellId);
1677                if(!spellInfo)
1678                {
1679                    sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId);
1680                    const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
1681                    const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
1682                    const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
1683                }
1684                // allowed only in special format
1685                else if(proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN)
1686                {
1687                    sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId);
1688                    const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
1689                    const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
1690                    const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
1691                }
1692            }
1693
1694            // spell_3*,spell_4*,spell_5* is empty
1695            for (int j = 2; j < 5; j++)
1696            {
1697                if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
1698                {
1699                    sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger);
1700                    const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
1701                    const_cast<ItemPrototype*>(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
1702                }
1703                else if(proto->Spells[j].SpellId != 0)
1704                {
1705                    sLog.outErrorDb("Item (Entry: %u) has wrong spell in spellid_%d (%u) for learning special format",i,j+1,proto->Spells[j].SpellId);
1706                    const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
1707                }
1708            }
1709        }
1710        // normal spell list
1711        else
1712        {
1713            for (int j = 0; j < 5; j++)
1714            {
1715                if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
1716                {
1717                    sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger);
1718                    const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
1719                    const_cast<ItemPrototype*>(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
1720                }
1721
1722                if(proto->Spells[j].SpellId)
1723                {
1724                    SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId);
1725                    if(!spellInfo)
1726                    {
1727                        sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
1728                        const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
1729                    }
1730                    // allowed only in special format
1731                    else if(proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN)
1732                    {
1733                        sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
1734                        const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
1735                    }
1736                }
1737            }
1738        }
1739
1740        if(proto->Bonding >= MAX_BIND_TYPE)
1741            sLog.outErrorDb("Item (Entry: %u) has wrong Bonding value (%u)",i,proto->Bonding);
1742
1743        if(proto->PageText && !sPageTextStore.LookupEntry<PageText>(proto->PageText))
1744            sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText);
1745
1746        if(proto->LockID && !sLockStore.LookupEntry(proto->LockID))
1747            sLog.outErrorDb("Item (Entry: %u) has wrong LockID (%u)",i,proto->LockID);
1748
1749        if(proto->Sheath >= MAX_SHEATHETYPE)
1750        {
1751            sLog.outErrorDb("Item (Entry: %u) has wrong Sheath (%u)",i,proto->Sheath);
1752            const_cast<ItemPrototype*>(proto)->Sheath = SHEATHETYPE_NONE;
1753        }
1754
1755        if(proto->RandomProperty && !sItemRandomPropertiesStore.LookupEntry(GetItemEnchantMod(proto->RandomProperty)))
1756        {
1757            sLog.outErrorDb("Item (Entry: %u) has unknown (wrong or not listed in `item_enchantment_template`) RandomProperty (%u)",i,proto->RandomProperty);
1758            const_cast<ItemPrototype*>(proto)->RandomProperty = 0;
1759        }
1760
1761        if(proto->RandomSuffix && !sItemRandomSuffixStore.LookupEntry(GetItemEnchantMod(proto->RandomSuffix)))
1762        {
1763            sLog.outErrorDb("Item (Entry: %u) has wrong RandomSuffix (%u)",i,proto->RandomSuffix);
1764            const_cast<ItemPrototype*>(proto)->RandomSuffix = 0;
1765        }
1766
1767        if(proto->ItemSet && !sItemSetStore.LookupEntry(proto->ItemSet))
1768        {
1769            sLog.outErrorDb("Item (Entry: %u) have wrong ItemSet (%u)",i,proto->ItemSet);
1770            const_cast<ItemPrototype*>(proto)->ItemSet = 0;
1771        }
1772
1773        if(proto->Area && !GetAreaEntryByAreaID(proto->Area))
1774            sLog.outErrorDb("Item (Entry: %u) has wrong Area (%u)",i,proto->Area);
1775
1776        if(proto->Map && !sMapStore.LookupEntry(proto->Map))
1777            sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map);
1778
1779        if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory))
1780            sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory);
1781
1782        for (int j = 0; j < 3; j++)
1783        {
1784            if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color)
1785            {
1786                sLog.outErrorDb("Item (Entry: %u) has wrong socketColor_%d (%u)",i,j+1,proto->Socket[j].Color);
1787                const_cast<ItemPrototype*>(proto)->Socket[j].Color = 0;
1788            }
1789        }
1790
1791        if(proto->GemProperties && !sGemPropertiesStore.LookupEntry(proto->GemProperties))
1792            sLog.outErrorDb("Item (Entry: %u) has wrong GemProperties (%u)",i,proto->GemProperties);
1793
1794        if(proto->FoodType >= MAX_PET_DIET)
1795        {
1796            sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType);
1797            const_cast<ItemPrototype*>(proto)->FoodType = 0;
1798        }
1799    }
1800
1801    // this DBC used currently only for check item templates in DB.
1802    sItemStore.Clear();
1803}
1804
1805void ObjectMgr::LoadAuctionItems()
1806{
1807    QueryResult *result = CharacterDatabase.Query( "SELECT itemguid,item_template FROM auctionhouse" );
1808
1809    if( !result )
1810        return;
1811
1812    barGoLink bar( result->GetRowCount() );
1813
1814    uint32 count = 0;
1815
1816    Field *fields;
1817    do
1818    {
1819        bar.step();
1820
1821        fields = result->Fetch();
1822        uint32 item_guid        = fields[0].GetUInt32();
1823        uint32 item_template    = fields[1].GetUInt32();
1824
1825        ItemPrototype const *proto = GetItemPrototype(item_template);
1826
1827        if(!proto)
1828        {
1829            sLog.outError( "ObjectMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped.", item_guid,item_template);
1830            continue;
1831        }
1832
1833        Item *item = NewItemOrBag(proto);
1834
1835        if(!item->LoadFromDB(item_guid,0))
1836        {
1837            delete item;
1838            continue;
1839        }
1840        AddAItem(item);
1841
1842        ++count;
1843    }
1844    while( result->NextRow() );
1845
1846    delete result;
1847
1848    sLog.outString();
1849    sLog.outString( ">> Loaded %u auction items", count );
1850}
1851
1852void ObjectMgr::LoadPetLevelInfo()
1853{
1854    // Loading levels data
1855    {
1856        //                                                 0               1      2   3     4    5    6    7     8    9
1857        QueryResult *result  = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats");
1858
1859        uint32 count = 0;
1860
1861        if (!result)
1862        {
1863            barGoLink bar( 1 );
1864
1865            sLog.outString();
1866            sLog.outString( ">> Loaded %u level pet stats definitions", count );
1867            sLog.outErrorDb( "Error loading `pet_levelstats` table or empty table.");
1868            return;
1869        }
1870
1871        barGoLink bar( result->GetRowCount() );
1872
1873        do
1874        {
1875            Field* fields = result->Fetch();
1876
1877            uint32 creature_id = fields[0].GetUInt32();
1878            if(!sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
1879            {
1880                sLog.outErrorDb("Wrong creature id %u in `pet_levelstats` table, ignoring.",creature_id);
1881                continue;
1882            }
1883
1884            uint32 current_level = fields[1].GetUInt32();
1885            if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
1886            {
1887                if(current_level > 255)                     // hardcoded level maximum
1888                    sLog.outErrorDb("Wrong (> 255) level %u in `pet_levelstats` table, ignoring.",current_level);
1889                else
1890                    sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `pet_levelstats` table, ignoring.",current_level);
1891                continue;
1892            }
1893            else if(current_level < 1)
1894            {
1895                sLog.outErrorDb("Wrong (<1) level %u in `pet_levelstats` table, ignoring.",current_level);
1896                continue;
1897            }
1898
1899            PetLevelInfo*& pInfoMapEntry = petInfo[creature_id];
1900
1901            if(pInfoMapEntry==NULL)
1902                pInfoMapEntry =  new PetLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
1903
1904            // data for level 1 stored in [0] array element, ...
1905            PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level-1];
1906
1907            pLevelInfo->health = fields[2].GetUInt16();
1908            pLevelInfo->mana   = fields[3].GetUInt16();
1909            pLevelInfo->armor  = fields[9].GetUInt16();
1910
1911            for (int i = 0; i < MAX_STATS; i++)
1912            {
1913                pLevelInfo->stats[i] = fields[i+4].GetUInt16();
1914            }
1915
1916            bar.step();
1917            ++count;
1918        }
1919        while (result->NextRow());
1920
1921        delete result;
1922
1923        sLog.outString();
1924        sLog.outString( ">> Loaded %u level pet stats definitions", count );
1925    }
1926
1927    // Fill gaps and check integrity
1928    for (PetLevelInfoMap::iterator itr = petInfo.begin(); itr != petInfo.end(); ++itr)
1929    {
1930        PetLevelInfo* pInfo = itr->second;
1931
1932        // fatal error if no level 1 data
1933        if(!pInfo || pInfo[0].health == 0 )
1934        {
1935            sLog.outErrorDb("Creature %u does not have pet stats data for Level 1!",itr->first);
1936            exit(1);
1937        }
1938
1939        // fill level gaps
1940        for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
1941        {
1942            if(pInfo[level].health == 0)
1943            {
1944                sLog.outErrorDb("Creature %u has no data for Level %i pet stats data, using data of Level %i.",itr->first,level+1, level);
1945                pInfo[level] = pInfo[level-1];
1946            }
1947        }
1948    }
1949}
1950
1951PetLevelInfo const* ObjectMgr::GetPetLevelInfo(uint32 creature_id, uint32 level) const
1952{
1953    if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
1954        level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
1955
1956    PetLevelInfoMap::const_iterator itr = petInfo.find(creature_id);
1957    if(itr == petInfo.end())
1958        return NULL;
1959
1960    return &itr->second[level-1];                           // data for level 1 stored in [0] array element, ...
1961}
1962
1963void ObjectMgr::LoadPlayerInfo()
1964{
1965    // Load playercreate
1966    {
1967        //                                                0     1      2    3     4           5           6
1968        QueryResult *result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z FROM playercreateinfo");
1969
1970        uint32 count = 0;
1971
1972        if (!result)
1973        {
1974            barGoLink bar( 1 );
1975
1976            sLog.outString();
1977            sLog.outString( ">> Loaded %u player create definitions", count );
1978            sLog.outErrorDb( "Error loading `playercreateinfo` table or empty table.");
1979            exit(1);
1980        }
1981
1982        barGoLink bar( result->GetRowCount() );
1983
1984        do
1985        {
1986            Field* fields = result->Fetch();
1987
1988            uint32 current_race = fields[0].GetUInt32();
1989            uint32 current_class = fields[1].GetUInt32();
1990            uint32 mapId     = fields[2].GetUInt32();
1991            uint32 zoneId    = fields[3].GetUInt32();
1992            float  positionX = fields[4].GetFloat();
1993            float  positionY = fields[5].GetFloat();
1994            float  positionZ = fields[6].GetFloat();
1995
1996            if(current_race >= MAX_RACES)
1997            {
1998                sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race);
1999                continue;
2000            }
2001
2002            ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(current_race);
2003            if(!rEntry)
2004            {
2005                sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race);
2006                continue;
2007            }
2008
2009            if(current_class >= MAX_CLASSES)
2010            {
2011                sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class);
2012                continue;
2013            }
2014
2015            if(!sChrClassesStore.LookupEntry(current_class))
2016            {
2017                sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class);
2018                continue;
2019            }
2020
2021            // accept DB data only for valid position (and non instanceable)
2022            if( !MapManager::IsValidMapCoord(mapId,positionX,positionY,positionZ) )
2023            {
2024                sLog.outErrorDb("Wrong home position for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race);
2025                continue;
2026            }
2027
2028            if( sMapStore.LookupEntry(mapId)->Instanceable() )
2029            {
2030                sLog.outErrorDb("Home position in instanceable map for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race);
2031                continue;
2032            }
2033
2034            PlayerInfo* pInfo = &playerInfo[current_race][current_class];
2035
2036            pInfo->mapId     = mapId;
2037            pInfo->zoneId    = zoneId;
2038            pInfo->positionX = positionX;
2039            pInfo->positionY = positionY;
2040            pInfo->positionZ = positionZ;
2041
2042            pInfo->displayId_m = rEntry->model_m;
2043            pInfo->displayId_f = rEntry->model_f;
2044
2045            bar.step();
2046            ++count;
2047        }
2048        while (result->NextRow());
2049
2050        delete result;
2051
2052        sLog.outString();
2053        sLog.outString( ">> Loaded %u player create definitions", count );
2054    }
2055
2056    // Load playercreate items
2057    {
2058        //                                                0     1      2       3
2059        QueryResult *result = WorldDatabase.Query("SELECT race, class, itemid, amount FROM playercreateinfo_item");
2060
2061        uint32 count = 0;
2062
2063        if (!result)
2064        {
2065            barGoLink bar( 1 );
2066
2067            sLog.outString();
2068            sLog.outString( ">> Loaded %u player create items", count );
2069            sLog.outErrorDb( "Error loading `playercreateinfo_item` table or empty table.");
2070        }
2071        else
2072        {
2073            barGoLink bar( result->GetRowCount() );
2074
2075            do
2076            {
2077                Field* fields = result->Fetch();
2078
2079                uint32 current_race = fields[0].GetUInt32();
2080                if(current_race >= MAX_RACES)
2081                {
2082                    sLog.outErrorDb("Wrong race %u in `playercreateinfo_item` table, ignoring.",current_race);
2083                    continue;
2084                }
2085
2086                uint32 current_class = fields[1].GetUInt32();
2087                if(current_class >= MAX_CLASSES)
2088                {
2089                    sLog.outErrorDb("Wrong class %u in `playercreateinfo_item` table, ignoring.",current_class);
2090                    continue;
2091                }
2092
2093                PlayerInfo* pInfo = &playerInfo[current_race][current_class];
2094
2095                uint32 item_id = fields[2].GetUInt32();
2096
2097                if(!GetItemPrototype(item_id))
2098                {
2099                    sLog.outErrorDb("Item id %u (race %u class %u) in `playercreateinfo_item` table but not listed in `item_template`, ignoring.",item_id,current_race,current_class);
2100                    continue;
2101                }
2102
2103                uint32 amount  = fields[3].GetUInt32();
2104
2105                if(!amount)
2106                {
2107                    sLog.outErrorDb("Item id %u (class %u race %u) have amount==0 in `playercreateinfo_item` table, ignoring.",item_id,current_race,current_class);
2108                    continue;
2109                }
2110
2111                pInfo->item.push_back(PlayerCreateInfoItem( item_id, amount));
2112
2113                bar.step();
2114                ++count;
2115            }
2116            while(result->NextRow());
2117
2118            delete result;
2119
2120            sLog.outString();
2121            sLog.outString( ">> Loaded %u player create items", count );
2122        }
2123    }
2124
2125    // Load playercreate spells
2126    {
2127
2128        QueryResult *result = NULL;
2129        if(sWorld.getConfig(CONFIG_START_ALL_SPELLS))
2130            result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell_custom");
2131        else
2132            result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell");
2133
2134        uint32 count = 0;
2135
2136        if (!result)
2137        {
2138            barGoLink bar( 1 );
2139
2140            sLog.outString();
2141            sLog.outString( ">> Loaded %u player create spells", count );
2142            sLog.outErrorDb( "Error loading player starting spells or empty table.");
2143        }
2144        else
2145        {
2146            barGoLink bar( result->GetRowCount() );
2147
2148            do
2149            {
2150                Field* fields = result->Fetch();
2151
2152                uint32 current_race = fields[0].GetUInt32();
2153                if(current_race >= MAX_RACES)
2154                {
2155                    sLog.outErrorDb("Wrong race %u in `playercreateinfo_spell` table, ignoring.",current_race);
2156                    continue;
2157                }
2158
2159                uint32 current_class = fields[1].GetUInt32();
2160                if(current_class >= MAX_CLASSES)
2161                {
2162                    sLog.outErrorDb("Wrong class %u in `playercreateinfo_spell` table, ignoring.",current_class);
2163                    continue;
2164                }
2165
2166                PlayerInfo* pInfo = &playerInfo[current_race][current_class];
2167                pInfo->spell.push_back(CreateSpellPair(fields[2].GetUInt16(), fields[3].GetUInt8()));
2168
2169                bar.step();
2170                ++count;
2171            }
2172            while( result->NextRow() );
2173
2174            delete result;
2175
2176            sLog.outString();
2177            sLog.outString( ">> Loaded %u player create spells", count );
2178        }
2179    }
2180
2181    // Load playercreate actions
2182    {
2183        //                                                0     1      2       3       4     5
2184        QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type, misc FROM playercreateinfo_action");
2185
2186        uint32 count = 0;
2187
2188        if (!result)
2189        {
2190            barGoLink bar( 1 );
2191
2192            sLog.outString();
2193            sLog.outString( ">> Loaded %u player create actions", count );
2194            sLog.outErrorDb( "Error loading `playercreateinfo_action` table or empty table.");
2195        }
2196        else
2197        {
2198            barGoLink bar( result->GetRowCount() );
2199
2200            do
2201            {
2202                Field* fields = result->Fetch();
2203
2204                uint32 current_race = fields[0].GetUInt32();
2205                if(current_race >= MAX_RACES)
2206                {
2207                    sLog.outErrorDb("Wrong race %u in `playercreateinfo_action` table, ignoring.",current_race);
2208                    continue;
2209                }
2210
2211                uint32 current_class = fields[1].GetUInt32();
2212                if(current_class >= MAX_CLASSES)
2213                {
2214                    sLog.outErrorDb("Wrong class %u in `playercreateinfo_action` table, ignoring.",current_class);
2215                    continue;
2216                }
2217
2218                PlayerInfo* pInfo = &playerInfo[current_race][current_class];
2219                pInfo->action[0].push_back(fields[2].GetUInt16());
2220                pInfo->action[1].push_back(fields[3].GetUInt16());
2221                pInfo->action[2].push_back(fields[4].GetUInt16());
2222                pInfo->action[3].push_back(fields[5].GetUInt16());
2223
2224                bar.step();
2225                ++count;
2226            }
2227            while( result->NextRow() );
2228
2229            delete result;
2230
2231            sLog.outString();
2232            sLog.outString( ">> Loaded %u player create actions", count );
2233        }
2234    }
2235
2236    // Loading levels data (class only dependent)
2237    {
2238        //                                                 0      1      2       3
2239        QueryResult *result  = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats");
2240
2241        uint32 count = 0;
2242
2243        if (!result)
2244        {
2245            barGoLink bar( 1 );
2246
2247            sLog.outString();
2248            sLog.outString( ">> Loaded %u level health/mana definitions", count );
2249            sLog.outErrorDb( "Error loading `player_classlevelstats` table or empty table.");
2250            exit(1);
2251        }
2252
2253        barGoLink bar( result->GetRowCount() );
2254
2255        do
2256        {
2257            Field* fields = result->Fetch();
2258
2259            uint32 current_class = fields[0].GetUInt32();
2260            if(current_class >= MAX_CLASSES)
2261            {
2262                sLog.outErrorDb("Wrong class %u in `player_classlevelstats` table, ignoring.",current_class);
2263                continue;
2264            }
2265
2266            uint32 current_level = fields[1].GetUInt32();
2267            if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
2268            {
2269                if(current_level > 255)                     // hardcoded level maximum
2270                    sLog.outErrorDb("Wrong (> 255) level %u in `player_classlevelstats` table, ignoring.",current_level);
2271                else
2272                    sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level);
2273                continue;
2274            }
2275
2276            PlayerClassInfo* pClassInfo = &playerClassInfo[current_class];
2277
2278            if(!pClassInfo->levelInfo)
2279                pClassInfo->levelInfo = new PlayerClassLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
2280
2281            PlayerClassLevelInfo* pClassLevelInfo = &pClassInfo->levelInfo[current_level-1];
2282
2283            pClassLevelInfo->basehealth = fields[2].GetUInt16();
2284            pClassLevelInfo->basemana   = fields[3].GetUInt16();
2285
2286            bar.step();
2287            ++count;
2288        }
2289        while (result->NextRow());
2290
2291        delete result;
2292
2293        sLog.outString();
2294        sLog.outString( ">> Loaded %u level health/mana definitions", count );
2295    }
2296
2297    // Fill gaps and check integrity
2298    for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
2299    {
2300        // skip non existed classes
2301        if(!sChrClassesStore.LookupEntry(class_))
2302            continue;
2303
2304        PlayerClassInfo* pClassInfo = &playerClassInfo[class_];
2305
2306        // fatal error if no level 1 data
2307        if(!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0 )
2308        {
2309            sLog.outErrorDb("Class %i Level 1 does not have health/mana data!",class_);
2310            exit(1);
2311        }
2312
2313        // fill level gaps
2314        for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
2315        {
2316            if(pClassInfo->levelInfo[level].basehealth == 0)
2317            {
2318                sLog.outErrorDb("Class %i Level %i does not have health/mana data. Using stats data of level %i.",class_,level+1, level);
2319                pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level-1];
2320            }
2321        }
2322    }
2323
2324    // Loading levels data (class/race dependent)
2325    {
2326        //                                                 0     1      2      3    4    5    6    7
2327        QueryResult *result  = WorldDatabase.Query("SELECT race, class, level, str, agi, sta, inte, spi FROM player_levelstats");
2328
2329        uint32 count = 0;
2330
2331        if (!result)
2332        {
2333            barGoLink bar( 1 );
2334
2335            sLog.outString();
2336            sLog.outString( ">> Loaded %u level stats definitions", count );
2337            sLog.outErrorDb( "Error loading `player_levelstats` table or empty table.");
2338            exit(1);
2339        }
2340
2341        barGoLink bar( result->GetRowCount() );
2342
2343        do
2344        {
2345            Field* fields = result->Fetch();
2346
2347            uint32 current_race = fields[0].GetUInt32();
2348            if(current_race >= MAX_RACES)
2349            {
2350                sLog.outErrorDb("Wrong race %u in `player_levelstats` table, ignoring.",current_race);
2351                continue;
2352            }
2353
2354            uint32 current_class = fields[1].GetUInt32();
2355            if(current_class >= MAX_CLASSES)
2356            {
2357                sLog.outErrorDb("Wrong class %u in `player_levelstats` table, ignoring.",current_class);
2358                continue;
2359            }
2360
2361            uint32 current_level = fields[2].GetUInt32();
2362            if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
2363            {
2364                if(current_level > 255)                     // hardcoded level maximum
2365                    sLog.outErrorDb("Wrong (> 255) level %u in `player_levelstats` table, ignoring.",current_level);
2366                else
2367                    sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_levelstats` table, ignoring.",current_level);
2368                continue;
2369            }
2370
2371            PlayerInfo* pInfo = &playerInfo[current_race][current_class];
2372
2373            if(!pInfo->levelInfo)
2374                pInfo->levelInfo = new PlayerLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
2375
2376            PlayerLevelInfo* pLevelInfo = &pInfo->levelInfo[current_level-1];
2377
2378            for (int i = 0; i < MAX_STATS; i++)
2379            {
2380                pLevelInfo->stats[i] = fields[i+3].GetUInt8();
2381            }
2382
2383            bar.step();
2384            ++count;
2385        }
2386        while (result->NextRow());
2387
2388        delete result;
2389
2390        sLog.outString();
2391        sLog.outString( ">> Loaded %u level stats definitions", count );
2392    }
2393
2394    // Fill gaps and check integrity
2395    for (int race = 0; race < MAX_RACES; ++race)
2396    {
2397        // skip non existed races
2398        if(!sChrRacesStore.LookupEntry(race))
2399            continue;
2400
2401        for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
2402        {
2403            // skip non existed classes
2404            if(!sChrClassesStore.LookupEntry(class_))
2405                continue;
2406
2407            PlayerInfo* pInfo = &playerInfo[race][class_];
2408
2409            // skip non loaded combinations
2410            if(!pInfo->displayId_m || !pInfo->displayId_f)
2411                continue;
2412
2413            // skip expansion races if not playing with expansion
2414            if (sWorld.getConfig(CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI))
2415                continue;
2416               
2417            // skip expansion classes if not playing with expansion
2418            if (sWorld.getConfig(CONFIG_EXPANSION) < 2 && class_ == CLASS_DEATH_KNIGHT)
2419                continue;
2420
2421            // fatal error if no level 1 data
2422            if(!pInfo->levelInfo || pInfo->levelInfo[0].stats[0] == 0 )
2423            {
2424                sLog.outErrorDb("Race %i Class %i Level 1 does not have stats data!",race,class_);
2425                exit(1);
2426            }
2427
2428            // fill level gaps
2429            for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
2430            {
2431                if(pInfo->levelInfo[level].stats[0] == 0)
2432                {
2433                    sLog.outErrorDb("Race %i Class %i Level %i does not have stats data. Using stats data of level %i.",race,class_,level+1, level);
2434                    pInfo->levelInfo[level] = pInfo->levelInfo[level-1];
2435                }
2436            }
2437        }
2438    }
2439}
2440
2441void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const
2442{
2443    if(level < 1 || class_ >= MAX_CLASSES)
2444        return;
2445
2446    PlayerClassInfo const* pInfo = &playerClassInfo[class_];
2447
2448    if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
2449        level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
2450
2451    *info = pInfo->levelInfo[level-1];
2452}
2453
2454void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint32 level, PlayerLevelInfo* info) const
2455{
2456    if(level < 1 || race   >= MAX_RACES || class_ >= MAX_CLASSES)
2457        return;
2458
2459    PlayerInfo const* pInfo = &playerInfo[race][class_];
2460    if(pInfo->displayId_m==0 || pInfo->displayId_f==0)
2461        return;
2462
2463    if(level <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
2464        *info = pInfo->levelInfo[level-1];
2465    else
2466        BuildPlayerLevelInfo(race,class_,level,info);
2467}
2468
2469void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, PlayerLevelInfo* info) const
2470{
2471    // base data (last known level)
2472    *info = playerInfo[race][_class].levelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1];
2473
2474    for(int lvl = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1; lvl < level; ++lvl)
2475    {
2476        switch(_class)
2477        {
2478            case CLASS_WARRIOR:
2479                info->stats[STAT_STRENGTH]  += (lvl > 23 ? 2: (lvl > 1  ? 1: 0));
2480                info->stats[STAT_STAMINA]   += (lvl > 23 ? 2: (lvl > 1  ? 1: 0));
2481                info->stats[STAT_AGILITY]   += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
2482                info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0);
2483                info->stats[STAT_SPIRIT]    += (lvl > 9 && !(lvl%2) ? 1: 0);
2484                break;
2485            case CLASS_PALADIN:
2486                info->stats[STAT_STRENGTH]  += (lvl > 3  ? 1: 0);
2487                info->stats[STAT_STAMINA]   += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
2488                info->stats[STAT_AGILITY]   += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0));
2489                info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0);
2490                info->stats[STAT_SPIRIT]    += (lvl > 7 ? 1: 0);
2491                break;
2492            case CLASS_HUNTER:
2493                info->stats[STAT_STRENGTH]  += (lvl > 4  ? 1: 0);
2494                info->stats[STAT_STAMINA]   += (lvl > 4  ? 1: 0);
2495                info->stats[STAT_AGILITY]   += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
2496                info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0);
2497                info->stats[STAT_SPIRIT]    += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
2498                break;
2499            case CLASS_ROGUE:
2500                info->stats[STAT_STRENGTH]  += (lvl > 5  ? 1: 0);
2501                info->stats[STAT_STAMINA]   += (lvl > 4  ? 1: 0);
2502                info->stats[STAT_AGILITY]   += (lvl > 16 ? 2: (lvl > 1 ? 1: 0));
2503                info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0);
2504                info->stats[STAT_SPIRIT]    += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
2505                break;
2506            case CLASS_PRIEST:
2507                info->stats[STAT_STRENGTH]  += (lvl > 9 && !(lvl%2) ? 1: 0);
2508                info->stats[STAT_STAMINA]   += (lvl > 5  ? 1: 0);
2509                info->stats[STAT_AGILITY]   += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0));
2510                info->stats[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0));
2511                info->stats[STAT_SPIRIT]    += (lvl > 3  ? 1: 0);
2512                break;
2513            case CLASS_SHAMAN:
2514                info->stats[STAT_STRENGTH]  += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
2515                info->stats[STAT_STAMINA]   += (lvl > 4 ? 1: 0);
2516                info->stats[STAT_AGILITY]   += (lvl > 7 && !(lvl%2) ? 1: 0);
2517                info->stats[STAT_INTELLECT] += (lvl > 5 ? 1: 0);
2518                info->stats[STAT_SPIRIT]    += (lvl > 4 ? 1: 0);
2519                break;
2520            case CLASS_MAGE:
2521                info->stats[STAT_STRENGTH]  += (lvl > 9 && !(lvl%2) ? 1: 0);
2522                info->stats[STAT_STAMINA]   += (lvl > 5  ? 1: 0);
2523                info->stats[STAT_AGILITY]   += (lvl > 9 && !(lvl%2) ? 1: 0);
2524                info->stats[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0));
2525                info->stats[STAT_SPIRIT]    += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
2526                break;
2527            case CLASS_WARLOCK:
2528                info->stats[STAT_STRENGTH]  += (lvl > 9 && !(lvl%2) ? 1: 0);
2529                info->stats[STAT_STAMINA]   += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
2530                info->stats[STAT_AGILITY]   += (lvl > 9 && !(lvl%2) ? 1: 0);
2531                info->stats[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
2532                info->stats[STAT_SPIRIT]    += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
2533                break;
2534            case CLASS_DRUID:
2535                info->stats[STAT_STRENGTH]  += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0));
2536                info->stats[STAT_STAMINA]   += (lvl > 32 ? 2: (lvl > 4 ? 1: 0));
2537                info->stats[STAT_AGILITY]   += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0));
2538                info->stats[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0));
2539                info->stats[STAT_SPIRIT]    += (lvl > 38 ? 3: (lvl > 5 ? 1: 0));
2540        }
2541    }
2542}
2543
2544void ObjectMgr::LoadGuilds()
2545{
2546    Guild *newguild;
2547    uint32 count = 0;
2548
2549    QueryResult *result = CharacterDatabase.Query( "SELECT guildid FROM guild" );
2550
2551    if( !result )
2552    {
2553
2554        barGoLink bar( 1 );
2555
2556        bar.step();
2557
2558        sLog.outString();
2559        sLog.outString( ">> Loaded %u guild definitions", count );
2560        return;
2561    }
2562
2563    barGoLink bar( result->GetRowCount() );
2564
2565    do
2566    {
2567        Field *fields = result->Fetch();
2568
2569        bar.step();
2570        ++count;
2571
2572        newguild = new Guild;
2573        if(!newguild->LoadGuildFromDB(fields[0].GetUInt32()))
2574        {
2575            newguild->Disband();
2576            delete newguild;
2577            continue;
2578        }
2579        AddGuild(newguild);
2580
2581    }while( result->NextRow() );
2582
2583    delete result;
2584
2585    sLog.outString();
2586    sLog.outString( ">> Loaded %u guild definitions", count );
2587}
2588
2589void ObjectMgr::LoadArenaTeams()
2590{
2591    uint32 count = 0;
2592
2593    QueryResult *result = CharacterDatabase.Query( "SELECT arenateamid FROM arena_team" );
2594
2595    if( !result )
2596    {
2597
2598        barGoLink bar( 1 );
2599
2600        bar.step();
2601
2602        sLog.outString();
2603        sLog.outString( ">> Loaded %u arenateam definitions", count );
2604        return;
2605    }
2606
2607    barGoLink bar( result->GetRowCount() );
2608
2609    do
2610    {
2611        Field *fields = result->Fetch();
2612
2613        bar.step();
2614        ++count;
2615
2616        ArenaTeam *newarenateam = new ArenaTeam;
2617        if(!newarenateam->LoadArenaTeamFromDB(fields[0].GetUInt32()))
2618        {
2619            delete newarenateam;
2620            continue;
2621        }
2622        AddArenaTeam(newarenateam);
2623    }while( result->NextRow() );
2624
2625    delete result;
2626
2627    sLog.outString();
2628    sLog.outString( ">> Loaded %u arenateam definitions", count );
2629}
2630
2631void ObjectMgr::LoadGroups()
2632{
2633    // -- loading groups --
2634    Group *group = NULL;
2635    uint64 leaderGuid = 0;
2636    uint32 count = 0;
2637    //                                                     0         1              2           3           4              5      6      7      8      9      10     11     12     13      14          15
2638    QueryResult *result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty, leaderGuid FROM groups");
2639
2640    if( !result )
2641    {
2642        barGoLink bar( 1 );
2643
2644        bar.step();
2645
2646        sLog.outString();
2647        sLog.outString( ">> Loaded %u group definitions", count );
2648        return;
2649    }
2650
2651    barGoLink bar( result->GetRowCount() );
2652
2653    do
2654    {
2655        bar.step();
2656        Field *fields = result->Fetch();
2657        ++count;
2658        leaderGuid = MAKE_NEW_GUID(fields[15].GetUInt32(),0,HIGHGUID_PLAYER);
2659
2660        group = new Group;
2661        if(!group->LoadGroupFromDB(leaderGuid, result, false))
2662        {
2663            group->Disband();
2664            delete group;
2665            continue;
2666        }
2667        AddGroup(group);
2668    }while( result->NextRow() );
2669
2670    delete result;
2671
2672    sLog.outString();
2673    sLog.outString( ">> Loaded %u group definitions", count );
2674
2675    // -- loading members --
2676    count = 0;
2677    group = NULL;
2678    leaderGuid = 0;
2679    //                                        0           1          2         3
2680    result = CharacterDatabase.PQuery("SELECT memberGuid, assistant, subgroup, leaderGuid FROM group_member ORDER BY leaderGuid");
2681    if(!result)
2682    {
2683        barGoLink bar( 1 );
2684        bar.step();
2685    }
2686    else
2687    {
2688        barGoLink bar( result->GetRowCount() );
2689        do
2690        {
2691            bar.step();
2692            Field *fields = result->Fetch();
2693            count++;
2694            leaderGuid = MAKE_NEW_GUID(fields[3].GetUInt32(), 0, HIGHGUID_PLAYER);
2695            if(!group || group->GetLeaderGUID() != leaderGuid)
2696            {
2697                group = GetGroupByLeader(leaderGuid);
2698                if(!group)
2699                {
2700                    sLog.outErrorDb("Incorrect entry in group_member table : no group with leader %d for member %d!", fields[3].GetUInt32(), fields[0].GetUInt32());
2701                    CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32());
2702                    continue;
2703                }
2704            }
2705
2706            if(!group->LoadMemberFromDB(fields[0].GetUInt32(), fields[2].GetUInt8(), fields[1].GetBool()))
2707            {
2708                sLog.outErrorDb("Incorrect entry in group_member table : member %d cannot be added to player %d's group!", fields[0].GetUInt32(), fields[3].GetUInt32());
2709                CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32());
2710            }
2711        }while( result->NextRow() );
2712        delete result;
2713    }
2714
2715    // clean groups
2716    // TODO: maybe delete from the DB before loading in this case
2717    for(GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end();)
2718    {
2719        if((*itr)->GetMembersCount() < 2)
2720        {
2721            (*itr)->Disband();
2722            delete *itr;
2723            mGroupSet.erase(itr++);
2724        }
2725        else
2726            ++itr;
2727    }
2728
2729    // -- loading instances --
2730    count = 0;
2731    group = NULL;
2732    leaderGuid = 0;
2733    result = CharacterDatabase.PQuery(
2734        //      0           1    2         3          4           5
2735        "SELECT leaderGuid, map, instance, permanent, difficulty, resettime, "
2736        // 6
2737        "(SELECT COUNT(*) FROM character_instance WHERE guid = leaderGuid AND instance = group_instance.instance AND permanent = 1 LIMIT 1) "
2738        "FROM group_instance LEFT JOIN instance ON instance = id ORDER BY leaderGuid"
2739    );
2740
2741    if(!result)
2742    {
2743        barGoLink bar( 1 );
2744        bar.step();
2745    }
2746    else
2747    {
2748        barGoLink bar( result->GetRowCount() );
2749        do
2750        {
2751            bar.step();
2752            Field *fields = result->Fetch();
2753            count++;
2754            leaderGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
2755            if(!group || group->GetLeaderGUID() != leaderGuid)
2756            {
2757                group = GetGroupByLeader(leaderGuid);
2758                if(!group)
2759                {
2760                    sLog.outErrorDb("Incorrect entry in group_instance table : no group with leader %d", fields[0].GetUInt32());
2761                    continue;
2762                }
2763            }
2764
2765            InstanceSave *save = sInstanceSaveManager.AddInstanceSave(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
2766            group->BindToInstance(save, fields[3].GetBool(), true);
2767        }while( result->NextRow() );
2768        delete result;
2769    }
2770
2771    sLog.outString();
2772    sLog.outString( ">> Loaded %u group-instance binds total", count );
2773
2774    sLog.outString();
2775    sLog.outString( ">> Loaded %u group members total", count );
2776}
2777
2778void ObjectMgr::LoadQuests()
2779{
2780    // For reload case
2781    for(QuestMap::const_iterator itr=mQuestTemplates.begin(); itr != mQuestTemplates.end(); ++itr)
2782        delete itr->second;
2783    mQuestTemplates.clear();
2784
2785    mExclusiveQuestGroups.clear();
2786
2787    //                                                0      1       2           3             4         5           6     7              8
2788    QueryResult *result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, SkillOrClass, MinLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue,"
2789    //   9                    10                 11                     12                   13                     14                   15                16
2790        "RepObjectiveFaction, RepObjectiveValue, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime,"
2791    //   17          18            19           20           21           22              23                24         25            26
2792        "QuestFlags, SpecialFlags, CharTitleId, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell,"
2793    //   27     28       29          30               31                32       33              34              35              36
2794        "Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4,"
2795    //   37          38          39          40          41             42             43             44
2796        "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4,"
2797    //   45            46            47            48            49               50               51               52               53             54             54             55
2798        "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4, ReqSourceRef1, ReqSourceRef2, ReqSourceRef3, ReqSourceRef4,"
2799    //   57                  58                  59                  60                  61                     62                     63                     64
2800        "ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4,"
2801    //   65             66             67             68
2802        "ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4,"
2803    //   69                70                71                72                73                74
2804        "RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6,"
2805    //   75                   76                   77                   78                   79                   80
2806        "RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6,"
2807    //   81          82          83          84          85             86             87             88
2808        "RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4,"
2809    //   89              90              91              92              93              94            95            96            97            98
2810        "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5,"
2811    //   99                 100            101               102       103           104                105               106         107     108    109
2812        "RewHonorableKills, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt,"
2813    //   110            111            112           113              114            115                116                117                118             119
2814        "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
2815    //   120            121
2816        "StartScript, CompleteScript"
2817        " FROM quest_template");
2818    if(result == NULL)
2819    {
2820        barGoLink bar( 1 );
2821        bar.step();
2822
2823        sLog.outString();
2824        sLog.outString( ">> Loaded 0 quests definitions" );
2825        sLog.outErrorDb("`quest_template` table is empty!");
2826        return;
2827    }
2828
2829    // create multimap previous quest for each existed quest
2830    // some quests can have many previous maps set by NextQuestId in previous quest
2831    // for example set of race quests can lead to single not race specific quest
2832    barGoLink bar( result->GetRowCount() );
2833    do
2834    {
2835        bar.step();
2836        Field *fields = result->Fetch();
2837
2838        Quest * newQuest = new Quest(fields);
2839        mQuestTemplates[newQuest->GetQuestId()] = newQuest;
2840    } while( result->NextRow() );
2841
2842    delete result;
2843
2844    // Post processing
2845    for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); iter++)
2846    {
2847        Quest * qinfo = iter->second;
2848
2849        // additional quest integrity checks (GO, creature_template and item_template must be loaded already)
2850
2851        if( qinfo->GetQuestMethod() >= 3 )
2852        {
2853            sLog.outErrorDb("Quest %u has `Method` = %u, expected values are 0, 1 or 2.",qinfo->GetQuestId(),qinfo->GetQuestMethod());
2854        }
2855
2856        if (qinfo->QuestFlags & ~QUEST_TRINITY_FLAGS_DB_ALLOWED)
2857        {
2858            sLog.outErrorDb("Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u",
2859                qinfo->GetQuestId(),qinfo->QuestFlags,QUEST_TRINITY_FLAGS_DB_ALLOWED >> 16);
2860            qinfo->QuestFlags &= QUEST_TRINITY_FLAGS_DB_ALLOWED;
2861        }
2862
2863        if(qinfo->QuestFlags & QUEST_FLAGS_DAILY)
2864        {
2865            if(!(qinfo->QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE))
2866            {
2867                sLog.outErrorDb("Daily Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId());
2868                qinfo->QuestFlags |= QUEST_TRINITY_FLAGS_REPEATABLE;
2869            }
2870        }
2871
2872        if(qinfo->QuestFlags & QUEST_FLAGS_AUTO_REWARDED)
2873        {
2874            // at auto-reward can be rewarded only RewChoiceItemId[0]
2875            for(int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j )
2876            {
2877                if(uint32 id = qinfo->RewChoiceItemId[j])
2878                {
2879                    sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item from `RewChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.",
2880                        qinfo->GetQuestId(),j+1,id,j+1);
2881                    // no changes, quest ignore this data
2882                }
2883            }
2884        }
2885
2886        // client quest log visual (area case)
2887        if( qinfo->ZoneOrSort > 0 )
2888        {
2889            if(!GetAreaEntryByAreaID(qinfo->ZoneOrSort))
2890            {
2891                sLog.outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
2892                    qinfo->GetQuestId(),qinfo->ZoneOrSort);
2893                // no changes, quest not dependent from this value but can have problems at client
2894            }
2895        }
2896        // client quest log visual (sort case)
2897        if( qinfo->ZoneOrSort < 0 )
2898        {
2899            QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort));
2900            if( !qSort )
2901            {
2902                sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.",
2903                    qinfo->GetQuestId(),qinfo->ZoneOrSort);
2904                // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check)
2905            }
2906            //check SkillOrClass value (class case).
2907            if( ClassByQuestSort(-int32(qinfo->ZoneOrSort)) )
2908            {
2909                // SkillOrClass should not have class case when class case already set in ZoneOrSort.
2910                if(qinfo->SkillOrClass < 0)
2911                {
2912                    sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClass` = %i (class case), redundant.",
2913                        qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClass);
2914                }
2915            }
2916            //check for proper SkillOrClass value (skill case)
2917            if(int32 skill_id =  SkillByQuestSort(-int32(qinfo->ZoneOrSort)))
2918            {
2919                // skill is positive value in SkillOrClass
2920                if(qinfo->SkillOrClass != skill_id )
2921                {
2922                    sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClass` does not have a corresponding value (%i).",
2923                        qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id);
2924                    //override, and force proper value here?
2925                }
2926            }
2927        }
2928
2929        // SkillOrClass (class case)
2930        if( qinfo->SkillOrClass < 0 )
2931        {
2932            if( !sChrClassesStore.LookupEntry(-int32(qinfo->SkillOrClass)) )
2933            {
2934                sLog.outErrorDb("Quest %u has `SkillOrClass` = %i (class case) but class (%i) does not exist",
2935                    qinfo->GetQuestId(),qinfo->SkillOrClass,-qinfo->SkillOrClass);
2936            }
2937        }
2938        // SkillOrClass (skill case)
2939        if( qinfo->SkillOrClass > 0 )
2940        {
2941            if( !sSkillLineStore.LookupEntry(qinfo->SkillOrClass) )
2942            {
2943                sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist",
2944                    qinfo->GetQuestId(),qinfo->SkillOrClass,qinfo->SkillOrClass);
2945            }
2946        }
2947
2948        if( qinfo->RequiredSkillValue )
2949        {
2950            if( qinfo->RequiredSkillValue > sWorld.GetConfigMaxSkillValue() )
2951            {
2952                sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but max possible skill is %u, quest can't be done.",
2953                    qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue());
2954                // no changes, quest can't be done for this requirement
2955            }
2956
2957            if( qinfo->SkillOrClass <= 0 )
2958            {
2959                sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.",
2960                    qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClass);
2961                // no changes, quest can't be done for this requirement (fail at wrong skill id)
2962            }
2963        }
2964        // else Skill quests can have 0 skill level, this is ok
2965
2966        if(qinfo->RepObjectiveFaction && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction))
2967        {
2968            sLog.outErrorDb("Quest %u has `RepObjectiveFaction` = %u but faction template %u does not exist, quest can't be done.",
2969                qinfo->GetQuestId(),qinfo->RepObjectiveFaction,qinfo->RepObjectiveFaction);
2970            // no changes, quest can't be done for this requirement
2971        }
2972
2973        if(qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction))
2974        {
2975            sLog.outErrorDb("Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.",
2976                qinfo->GetQuestId(),qinfo->RequiredMinRepFaction,qinfo->RequiredMinRepFaction);
2977            // no changes, quest can't be done for this requirement
2978        }
2979
2980        if(qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction))
2981        {
2982            sLog.outErrorDb("Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.",
2983                qinfo->GetQuestId(),qinfo->RequiredMaxRepFaction,qinfo->RequiredMaxRepFaction);
2984            // no changes, quest can't be done for this requirement
2985        }
2986
2987        if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > Player::Reputation_Cap)
2988        {
2989            sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.",
2990                qinfo->GetQuestId(),qinfo->RequiredMinRepValue,Player::Reputation_Cap);
2991            // no changes, quest can't be done for this requirement
2992        }
2993
2994        if(qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue)
2995        {
2996            sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.",
2997                qinfo->GetQuestId(),qinfo->RequiredMaxRepValue,qinfo->RequiredMinRepValue);
2998            // no changes, quest can't be done for this requirement
2999        }
3000
3001        if(!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0 )
3002        {
3003            sLog.outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect",
3004                qinfo->GetQuestId(),qinfo->RepObjectiveValue);
3005            // warning
3006        }
3007
3008        if(!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0 )
3009        {
3010            sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect",
3011                qinfo->GetQuestId(),qinfo->RequiredMinRepValue);
3012            // warning
3013        }
3014
3015        if(!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0 )
3016        {
3017            sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect",
3018                qinfo->GetQuestId(),qinfo->RequiredMaxRepValue);
3019            // warning
3020        }
3021
3022        if(qinfo->CharTitleId && !sCharTitlesStore.LookupEntry(qinfo->CharTitleId))
3023        {
3024            sLog.outErrorDb("Quest %u has `CharTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.",
3025                qinfo->GetQuestId(),qinfo->GetCharTitleId(),qinfo->GetCharTitleId());
3026            qinfo->CharTitleId = 0;
3027            // quest can't reward this title
3028        }
3029
3030        if(qinfo->SrcItemId)
3031        {
3032            if(!sItemStorage.LookupEntry<ItemPrototype>(qinfo->SrcItemId))
3033            {
3034                sLog.outErrorDb("Quest %u has `SrcItemId` = %u but item with entry %u does not exist, quest can't be done.",
3035                    qinfo->GetQuestId(),qinfo->SrcItemId,qinfo->SrcItemId);
3036                qinfo->SrcItemId = 0;                       // quest can't be done for this requirement
3037            }
3038            else if(qinfo->SrcItemCount==0)
3039            {
3040                sLog.outErrorDb("Quest %u has `SrcItemId` = %u but `SrcItemCount` = 0, set to 1 but need fix in DB.",
3041                    qinfo->GetQuestId(),qinfo->SrcItemId);
3042                qinfo->SrcItemCount = 1;                    // update to 1 for allow quest work for backward comptibility with DB
3043            }
3044        }
3045        else if(qinfo->SrcItemCount>0)
3046        {
3047            sLog.outErrorDb("Quest %u has `SrcItemId` = 0 but `SrcItemCount` = %u, useless value.",
3048                qinfo->GetQuestId(),qinfo->SrcItemCount);
3049            qinfo->SrcItemCount=0;                          // no quest work changes in fact
3050        }
3051
3052        if(qinfo->SrcSpell)
3053        {
3054            SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->SrcSpell);
3055            if(!spellInfo)
3056            {
3057                sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u doesn't exist, quest can't be done.",
3058                    qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell);
3059                qinfo->SrcSpell = 0;                        // quest can't be done for this requirement
3060            }
3061            else if(!SpellMgr::IsSpellValid(spellInfo))
3062            {
3063                sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u is broken, quest can't be done.",
3064                    qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell);
3065                qinfo->SrcSpell = 0;                        // quest can't be done for this requirement
3066            }
3067        }
3068
3069        for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
3070        {
3071            uint32 id = qinfo->ReqItemId[j];
3072            if(id)
3073            {
3074                if(qinfo->ReqItemCount[j]==0)
3075                {
3076                    sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but `ReqItemCount%d` = 0, quest can't be done.",
3077                        qinfo->GetQuestId(),j+1,id,j+1);
3078                    // no changes, quest can't be done for this requirement
3079                }
3080
3081                qinfo->SetFlag(QUEST_TRINITY_FLAGS_DELIVER);
3082
3083                if(!sItemStorage.LookupEntry<ItemPrototype>(id))
3084                {
3085                    sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but item with entry %u does not exist, quest can't be done.",
3086                        qinfo->GetQuestId(),j+1,id,id);
3087                    qinfo->ReqItemCount[j] = 0;             // prevent incorrect work of quest
3088                }
3089            }
3090            else if(qinfo->ReqItemCount[j]>0)
3091            {
3092                sLog.outErrorDb("Quest %u has `ReqItemId%d` = 0 but `ReqItemCount%d` = %u, quest can't be done.",
3093                    qinfo->GetQuestId(),j+1,j+1,qinfo->ReqItemCount[j]);
3094                qinfo->ReqItemCount[j] = 0;                 // prevent incorrect work of quest
3095            }
3096        }
3097
3098        for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
3099        {
3100            uint32 id = qinfo->ReqSourceId[j];
3101            if(id)
3102            {
3103                if(!sItemStorage.LookupEntry<ItemPrototype>(id))
3104                {
3105                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but item with entry %u does not exist, quest can't be done.",
3106                        qinfo->GetQuestId(),j+1,id,id);
3107                    // no changes, quest can't be done for this requirement
3108                }
3109
3110                if(!qinfo->ReqSourceCount[j])
3111                {
3112                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.",
3113                        qinfo->GetQuestId(),j+1,id,j+1);
3114                    qinfo->ReqSourceId[j] = 0;              // prevent incorrect work of quest
3115                }
3116
3117                if(!qinfo->ReqSourceRef[j])
3118                {
3119                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.",
3120                        qinfo->GetQuestId(),j+1,id,j+1);
3121                    qinfo->ReqSourceId[j] = 0;              // prevent incorrect work of quest
3122                }
3123            }
3124            else
3125            {
3126                if(qinfo->ReqSourceCount[j]>0)
3127                {
3128                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceCount%d` = %u.",
3129                        qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]);
3130                    // no changes, quest ignore this data
3131                }
3132
3133                if(qinfo->ReqSourceRef[j]>0)
3134                {
3135                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.",
3136                        qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]);
3137                    // no changes, quest ignore this data
3138                }
3139            }
3140        }
3141
3142        for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
3143        {
3144            uint32 ref = qinfo->ReqSourceRef[j];
3145            if(ref)
3146            {
3147                if(ref > QUEST_OBJECTIVES_COUNT)
3148                {
3149                    sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.",
3150                        qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT);
3151                    // no changes, quest can't be done for this requirement
3152                }
3153                else
3154                if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1])
3155                {
3156                    sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.",
3157                        qinfo->GetQuestId(),j+1,ref,ref,ref);
3158                    // no changes, quest can't be done for this requirement
3159                }
3160                else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1])
3161                {
3162                    sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.",
3163                        qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]);
3164                    // no changes, quest can't be done for this requirement
3165                    qinfo->ReqSourceId[j] = 0;              // prevent incorrect work of quest
3166                }
3167            }
3168        }
3169
3170        for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
3171        {
3172            uint32 id = qinfo->ReqSpell[j];
3173            if(id)
3174            {
3175                SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
3176                if(!spellInfo)
3177                {
3178                    sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.",
3179                        qinfo->GetQuestId(),j+1,id,id);
3180                    // no changes, quest can't be done for this requirement
3181                }
3182
3183                if(!qinfo->ReqCreatureOrGOId[j])
3184                {
3185                    bool found = false;
3186                    for(int k = 0; k < 3; ++k)
3187                    {
3188                        if( spellInfo->Effect[k]==SPELL_EFFECT_QUEST_COMPLETE && uint32(spellInfo->EffectMiscValue[k])==qinfo->QuestId ||
3189                            spellInfo->Effect[k]==SPELL_EFFECT_SEND_EVENT)
3190                        {
3191                            found = true;
3192                            break;
3193                        }
3194                    }
3195
3196                    if(found)
3197                    {
3198                        if(!qinfo->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
3199                        {
3200                            sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT for quest %u and ReqCreatureOrGOId%d = 0, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags or ReqCreatureOrGOId%d must be fixed, quest modified to enable objective.",spellInfo->Id,qinfo->QuestId,j+1,j+1);
3201
3202                            // this will prevent quest completing without objective
3203                            const_cast<Quest*>(qinfo)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
3204                        }
3205                    }
3206                    else
3207                    {
3208                        sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u and ReqCreatureOrGOId%d = 0 but spell %u does not have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT effect for this quest, quest can't be done.",
3209                            qinfo->GetQuestId(),j+1,id,j+1,id);
3210                        // no changes, quest can't be done for this requirement
3211                    }
3212                }
3213            }
3214        }
3215
3216        for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
3217        {
3218            int32 id = qinfo->ReqCreatureOrGOId[j];
3219            if(id < 0 && !sGOStorage.LookupEntry<GameObjectInfo>(-id))
3220            {
3221                sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but gameobject %u does not exist, quest can't be done.",
3222                    qinfo->GetQuestId(),j+1,id,uint32(-id));
3223                qinfo->ReqCreatureOrGOId[j] = 0;            // quest can't be done for this requirement
3224            }
3225
3226            if(id > 0 && !sCreatureStorage.LookupEntry<CreatureInfo>(id))
3227            {
3228                sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but creature with entry %u does not exist, quest can't be done.",
3229                    qinfo->GetQuestId(),j+1,id,uint32(id));
3230                qinfo->ReqCreatureOrGOId[j] = 0;            // quest can't be done for this requirement
3231            }
3232
3233            if(id)
3234            {
3235                // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast
3236
3237                qinfo->SetFlag(QUEST_TRINITY_FLAGS_KILL_OR_CAST | QUEST_TRINITY_FLAGS_SPEAKTO);
3238
3239                if(!qinfo->ReqCreatureOrGOCount[j])
3240                {
3241                    sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %u but `ReqCreatureOrGOCount%d` = 0, quest can't be done.",
3242                        qinfo->GetQuestId(),j+1,id,j+1);
3243                    // no changes, quest can be incorrectly done, but we already report this
3244                }
3245            }
3246            else if(qinfo->ReqCreatureOrGOCount[j]>0)
3247            {
3248                sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = 0 but `ReqCreatureOrGOCount%d` = %u.",
3249                    qinfo->GetQuestId(),j+1,j+1,qinfo->ReqCreatureOrGOCount[j]);
3250                // no changes, quest ignore this data
3251            }
3252        }
3253
3254        for(int j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j )
3255        {
3256            uint32 id = qinfo->RewChoiceItemId[j];
3257            if(id)
3258            {
3259                if(!sItemStorage.LookupEntry<ItemPrototype>(id))
3260                {
3261                    sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
3262                        qinfo->GetQuestId(),j+1,id,id);
3263                    qinfo->RewChoiceItemId[j] = 0;          // no changes, quest will not reward this
3264                }
3265
3266                if(!qinfo->RewChoiceItemCount[j])
3267                {
3268                    sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but `RewChoiceItemCount%d` = 0, quest can't be done.",
3269                        qinfo->GetQuestId(),j+1,id,j+1);
3270                    // no changes, quest can't be done
3271                }
3272            }
3273            else if(qinfo->RewChoiceItemCount[j]>0)
3274            {
3275                sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = 0 but `RewChoiceItemCount%d` = %u.",
3276                    qinfo->GetQuestId(),j+1,j+1,qinfo->RewChoiceItemCount[j]);
3277                // no changes, quest ignore this data
3278            }
3279        }
3280
3281        for(int j = 0; j < QUEST_REWARDS_COUNT; ++j )
3282        {
3283            uint32 id = qinfo->RewItemId[j];
3284            if(id)
3285            {
3286                if(!sItemStorage.LookupEntry<ItemPrototype>(id))
3287                {
3288                    sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
3289                        qinfo->GetQuestId(),j+1,id,id);
3290                    qinfo->RewItemId[j] = 0;                // no changes, quest will not reward this item
3291                }
3292
3293                if(!qinfo->RewItemCount[j])
3294                {
3295                    sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but `RewItemCount%d` = 0, quest will not reward this item.",
3296                        qinfo->GetQuestId(),j+1,id,j+1);
3297                    // no changes
3298                }
3299            }
3300            else if(qinfo->RewItemCount[j]>0)
3301            {
3302                sLog.outErrorDb("Quest %u has `RewItemId%d` = 0 but `RewItemCount%d` = %u.",
3303                    qinfo->GetQuestId(),j+1,j+1,qinfo->RewItemCount[j]);
3304                // no changes, quest ignore this data
3305            }
3306        }
3307
3308        for(int j = 0; j < QUEST_REPUTATIONS_COUNT; ++j)
3309        {
3310            if(qinfo->RewRepFaction[j])
3311            {
3312                if(!qinfo->RewRepValue[j])
3313                {
3314                    sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but `RewRepValue%d` = 0, quest will not reward this reputation.",
3315                        qinfo->GetQuestId(),j+1,qinfo->RewRepValue[j],j+1);
3316                    // no changes
3317                }
3318
3319                if(!sFactionStore.LookupEntry(qinfo->RewRepFaction[j]))
3320                {
3321                    sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but raw faction (faction.dbc) %u does not exist, quest will not reward reputation for this faction.",
3322                        qinfo->GetQuestId(),j+1,qinfo->RewRepFaction[j] ,qinfo->RewRepFaction[j] );
3323                    qinfo->RewRepFaction[j] = 0;            // quest will not reward this
3324                }
3325            }
3326            else if(qinfo->RewRepValue[j]!=0)
3327            {
3328                sLog.outErrorDb("Quest %u has `RewRepFaction%d` = 0 but `RewRepValue%d` = %u.",
3329                    qinfo->GetQuestId(),j+1,j+1,qinfo->RewRepValue[j]);
3330                // no changes, quest ignore this data
3331            }
3332        }
3333
3334        if(qinfo->RewSpell)
3335        {
3336            SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpell);
3337
3338            if(!spellInfo)
3339            {
3340                sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u does not exist, spell removed as display reward.",
3341                    qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
3342                qinfo->RewSpell = 0;                        // no spell reward will display for this quest
3343            }
3344
3345            else if(!SpellMgr::IsSpellValid(spellInfo))
3346            {
3347                sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.",
3348                    qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
3349                qinfo->RewSpell = 0;                        // no spell reward will display for this quest
3350            }
3351
3352        }
3353
3354        if(qinfo->RewSpellCast)
3355        {
3356            SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpellCast);
3357
3358            if(!spellInfo)
3359            {
3360                sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.",
3361                    qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
3362                qinfo->RewSpellCast = 0;                    // no spell will be casted on player
3363            }
3364
3365            else if(!SpellMgr::IsSpellValid(spellInfo))
3366            {
3367                sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.",
3368                    qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
3369                qinfo->RewSpellCast = 0;                    // no spell will be casted on player
3370            }
3371
3372        }
3373
3374        if(qinfo->RewMailTemplateId)
3375        {
3376            if(!sMailTemplateStore.LookupEntry(qinfo->RewMailTemplateId))
3377            {
3378                sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template  %u does not exist, quest will not have a mail reward.",
3379                    qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId);
3380                qinfo->RewMailTemplateId = 0;               // no mail will send to player
3381                qinfo->RewMailDelaySecs = 0;                // no mail will send to player
3382            }
3383        }
3384
3385        if(qinfo->NextQuestInChain)
3386        {
3387            if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end())
3388            {
3389                sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.",
3390                    qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain );
3391                qinfo->NextQuestInChain = 0;
3392            }
3393            else
3394                mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId());
3395        }
3396
3397        // fill additional data stores
3398        if(qinfo->PrevQuestId)
3399        {
3400            if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end())
3401            {
3402                sLog.outErrorDb("Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId());
3403            }
3404            else
3405            {
3406                qinfo->prevQuests.push_back(qinfo->PrevQuestId);
3407            }
3408        }
3409
3410        if(qinfo->NextQuestId)
3411        {
3412            if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end())
3413            {
3414                sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
3415            }
3416            else
3417            {
3418                int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
3419                mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId);
3420            }
3421        }
3422
3423        if(qinfo->ExclusiveGroup)
3424            mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId()));
3425        if(qinfo->LimitTime)
3426            qinfo->SetFlag(QUEST_TRINITY_FLAGS_TIMED);
3427    }
3428
3429    // check QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
3430    for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i)
3431    {
3432        SpellEntry const *spellInfo = sSpellStore.LookupEntry(i);
3433        if(!spellInfo)
3434            continue;
3435
3436        for(int j = 0; j < 3; ++j)
3437        {
3438            if(spellInfo->Effect[j] != SPELL_EFFECT_QUEST_COMPLETE)
3439                continue;
3440
3441            uint32 quest_id = spellInfo->EffectMiscValue[j];
3442
3443            Quest const* quest = GetQuestTemplate(quest_id);
3444
3445            // some quest referenced in spells not exist (outdataed spells)
3446            if(!quest)
3447                continue;
3448
3449            if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
3450            {
3451                sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE for quest %u , but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.",spellInfo->Id,quest_id);
3452
3453                // this will prevent quest completing without objective
3454                const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
3455            }
3456        }
3457    }
3458
3459    sLog.outString();
3460    sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() );
3461}
3462
3463void ObjectMgr::LoadQuestLocales()
3464{
3465    mQuestLocaleMap.clear();
3466
3467    QueryResult *result = WorldDatabase.Query("SELECT entry,"
3468        "Title_loc1,Details_loc1,Objectives_loc1,OfferRewardText_loc1,RequestItemsText_loc1,EndText_loc1,ObjectiveText1_loc1,ObjectiveText2_loc1,ObjectiveText3_loc1,ObjectiveText4_loc1,"
3469        "Title_loc2,Details_loc2,Objectives_loc2,OfferRewardText_loc2,RequestItemsText_loc2,EndText_loc2,ObjectiveText1_loc2,ObjectiveText2_loc2,ObjectiveText3_loc2,ObjectiveText4_loc2,"
3470        "Title_loc3,Details_loc3,Objectives_loc3,OfferRewardText_loc3,RequestItemsText_loc3,EndText_loc3,ObjectiveText1_loc3,ObjectiveText2_loc3,ObjectiveText3_loc3,ObjectiveText4_loc3,"
3471        "Title_loc4,Details_loc4,Objectives_loc4,OfferRewardText_loc4,RequestItemsText_loc4,EndText_loc4,ObjectiveText1_loc4,ObjectiveText2_loc4,ObjectiveText3_loc4,ObjectiveText4_loc4,"
3472        "Title_loc5,Details_loc5,Objectives_loc5,OfferRewardText_loc5,RequestItemsText_loc5,EndText_loc5,ObjectiveText1_loc5,ObjectiveText2_loc5,ObjectiveText3_loc5,ObjectiveText4_loc5,"
3473        "Title_loc6,Details_loc6,Objectives_loc6,OfferRewardText_loc6,RequestItemsText_loc6,EndText_loc6,ObjectiveText1_loc6,ObjectiveText2_loc6,ObjectiveText3_loc6,ObjectiveText4_loc6,"
3474        "Title_loc7,Details_loc7,Objectives_loc7,OfferRewardText_loc7,RequestItemsText_loc7,EndText_loc7,ObjectiveText1_loc7,ObjectiveText2_loc7,ObjectiveText3_loc7,ObjectiveText4_loc7,"
3475        "Title_loc8,Details_loc8,Objectives_loc8,OfferRewardText_loc8,RequestItemsText_loc8,EndText_loc8,ObjectiveText1_loc8,ObjectiveText2_loc8,ObjectiveText3_loc8,ObjectiveText4_loc8"
3476        " FROM locales_quest"
3477        );
3478
3479    if(!result)
3480    {
3481        barGoLink bar(1);
3482
3483        bar.step();
3484
3485        sLog.outString("");
3486        sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty.");
3487        return;
3488    }
3489
3490    barGoLink bar(result->GetRowCount());
3491
3492    do
3493    {
3494        Field *fields = result->Fetch();
3495        bar.step();
3496
3497        uint32 entry = fields[0].GetUInt32();
3498
3499        QuestLocale& data = mQuestLocaleMap[entry];
3500
3501        for(int i = 1; i < MAX_LOCALE; ++i)
3502        {
3503            std::string str = fields[1+10*(i-1)].GetCppString();
3504            if(!str.empty())
3505            {
3506                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3507                if(idx >= 0)
3508                {
3509                    if(data.Title.size() <= idx)
3510                        data.Title.resize(idx+1);
3511
3512                    data.Title[idx] = str;
3513                }
3514            }
3515            str = fields[1+10*(i-1)+1].GetCppString();
3516            if(!str.empty())
3517            {
3518                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3519                if(idx >= 0)
3520                {
3521                    if(data.Details.size() <= idx)
3522                        data.Details.resize(idx+1);
3523
3524                    data.Details[idx] = str;
3525                }
3526            }
3527            str = fields[1+10*(i-1)+2].GetCppString();
3528            if(!str.empty())
3529            {
3530                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3531                if(idx >= 0)
3532                {
3533                    if(data.Objectives.size() <= idx)
3534                        data.Objectives.resize(idx+1);
3535
3536                    data.Objectives[idx] = str;
3537                }
3538            }
3539            str = fields[1+10*(i-1)+3].GetCppString();
3540            if(!str.empty())
3541            {
3542                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3543                if(idx >= 0)
3544                {
3545                    if(data.OfferRewardText.size() <= idx)
3546                        data.OfferRewardText.resize(idx+1);
3547
3548                    data.OfferRewardText[idx] = str;
3549                }
3550            }
3551            str = fields[1+10*(i-1)+4].GetCppString();
3552            if(!str.empty())
3553            {
3554                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3555                if(idx >= 0)
3556                {
3557                    if(data.RequestItemsText.size() <= idx)
3558                        data.RequestItemsText.resize(idx+1);
3559
3560                    data.RequestItemsText[idx] = str;
3561                }
3562            }
3563            str = fields[1+10*(i-1)+5].GetCppString();
3564            if(!str.empty())
3565            {
3566                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3567                if(idx >= 0)
3568                {
3569                    if(data.EndText.size() <= idx)
3570                        data.EndText.resize(idx+1);
3571
3572                    data.EndText[idx] = str;
3573                }
3574            }
3575            for(int k = 0; k < 4; ++k)
3576            {
3577                str = fields[1+10*(i-1)+6+k].GetCppString();
3578                if(!str.empty())
3579                {
3580                    int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3581                    if(idx >= 0)
3582                    {
3583                        if(data.ObjectiveText[k].size() <= idx)
3584                            data.ObjectiveText[k].resize(idx+1);
3585
3586                        data.ObjectiveText[k][idx] = str;
3587                    }
3588                }
3589            }
3590        }
3591    } while (result->NextRow());
3592
3593    delete result;
3594
3595    sLog.outString();
3596    sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() );
3597}
3598
3599void ObjectMgr::LoadPetCreateSpells()
3600{
3601    QueryResult *result = WorldDatabase.PQuery("SELECT entry, Spell1, Spell2, Spell3, Spell4 FROM petcreateinfo_spell");
3602    if(!result)
3603    {
3604        barGoLink bar( 1 );
3605        bar.step();
3606
3607        sLog.outString();
3608        sLog.outString( ">> Loaded 0 pet create spells" );
3609        sLog.outErrorDb("`petcreateinfo_spell` table is empty!");
3610        return;
3611    }
3612
3613    uint32 count = 0;
3614
3615    barGoLink bar( result->GetRowCount() );
3616
3617    mPetCreateSpell.clear();
3618
3619    do
3620    {
3621        Field *fields = result->Fetch();
3622        bar.step();
3623
3624        uint32 creature_id = fields[0].GetUInt32();
3625
3626        if(!creature_id || !sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
3627            continue;
3628
3629        PetCreateSpellEntry PetCreateSpell;
3630        for(int i = 0; i < 4; i++)
3631        {
3632            PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32();
3633
3634            if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i]))
3635                sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]);
3636        }
3637
3638        mPetCreateSpell[creature_id] = PetCreateSpell;
3639
3640        ++count;
3641    }
3642    while (result->NextRow());
3643
3644    delete result;
3645
3646    sLog.outString();
3647    sLog.outString( ">> Loaded %u pet create spells", count );
3648}
3649
3650void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
3651{
3652    if(sWorld.IsScriptScheduled())                          // function don't must be called in time scripts use.
3653        return;
3654
3655    sLog.outString( "%s :", tablename);
3656
3657    scripts.clear();                                        // need for reload support
3658
3659    QueryResult *result = WorldDatabase.PQuery( "SELECT id,delay,command,datalong,datalong2,datatext, x, y, z, o FROM %s", tablename );
3660
3661    uint32 count = 0;
3662
3663    if( !result )
3664    {
3665        barGoLink bar( 1 );
3666        bar.step();
3667
3668        sLog.outString();
3669        sLog.outString( ">> Loaded %u script definitions", count );
3670        return;
3671    }
3672
3673    barGoLink bar( result->GetRowCount() );
3674
3675    do
3676    {
3677        bar.step();
3678
3679        Field *fields = result->Fetch();
3680        ScriptInfo tmp;
3681        tmp.id = fields[0].GetUInt32();
3682        tmp.delay = fields[1].GetUInt32();
3683        tmp.command = fields[2].GetUInt32();
3684        tmp.datalong = fields[3].GetUInt32();
3685        tmp.datalong2 = fields[4].GetUInt32();
3686        tmp.datatext = fields[5].GetCppString();
3687        tmp.x = fields[6].GetFloat();
3688        tmp.y = fields[7].GetFloat();
3689        tmp.z = fields[8].GetFloat();
3690        tmp.o = fields[9].GetFloat();
3691
3692        // generic command args check
3693        switch(tmp.command)
3694        {
3695            case SCRIPT_COMMAND_TALK:
3696            {
3697                if(tmp.datalong > 3)
3698                {
3699                    sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id);
3700                    continue;
3701                }
3702                break;
3703            }
3704
3705            case SCRIPT_COMMAND_TELEPORT_TO:
3706            {
3707                if(!sMapStore.LookupEntry(tmp.datalong))
3708                {
3709                    sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.datalong,tmp.id);
3710                    continue;
3711                }
3712
3713                if(!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
3714                {
3715                    sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.x,tmp.y,tmp.id);
3716                    continue;
3717                }
3718                break;
3719            }
3720
3721            case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
3722            {
3723                if(!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
3724                {
3725                    sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.x,tmp.y,tmp.id);
3726                    continue;
3727                }
3728
3729                if(!GetCreatureTemplate(tmp.datalong))
3730                {
3731                    sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.datalong,tmp.id);
3732                    continue;
3733                }
3734                break;
3735            }
3736
3737            case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
3738            {
3739                GameObjectData const* data = GetGOData(tmp.datalong);
3740                if(!data)
3741                {
3742                    sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,tmp.id);
3743                    continue;
3744                }
3745
3746                GameObjectInfo const* info = GetGameObjectInfo(data->id);
3747                if(!info)
3748                {
3749                    sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,data->id,tmp.id);
3750                    continue;
3751                }
3752
3753                if( info->type==GAMEOBJECT_TYPE_FISHINGNODE ||
3754                    info->type==GAMEOBJECT_TYPE_FISHINGHOLE ||
3755                    info->type==GAMEOBJECT_TYPE_DOOR        ||
3756                    info->type==GAMEOBJECT_TYPE_BUTTON      ||
3757                    info->type==GAMEOBJECT_TYPE_TRAP )
3758                {
3759                    sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,info->id,tmp.id);
3760                    continue;
3761                }
3762                break;
3763            }
3764            case SCRIPT_COMMAND_OPEN_DOOR:
3765            case SCRIPT_COMMAND_CLOSE_DOOR:
3766            {
3767                GameObjectData const* data = GetGOData(tmp.datalong);
3768                if(!data)
3769                {
3770                    sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",tablename,tmp.datalong,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
3771                    continue;
3772                }
3773
3774                GameObjectInfo const* info = GetGameObjectInfo(data->id);
3775                if(!info)
3776                {
3777                    sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",tablename,tmp.datalong,data->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
3778                    continue;
3779                }
3780
3781                if( info->type!=GAMEOBJECT_TYPE_DOOR)
3782                {
3783                    sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",tablename,info->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
3784                    continue;
3785                }
3786
3787                break;
3788            }
3789            case SCRIPT_COMMAND_QUEST_EXPLORED:
3790            {
3791                Quest const* quest = GetQuestTemplate(tmp.datalong);
3792                if(!quest)
3793                {
3794                    sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong,tmp.id);
3795                    continue;
3796                }
3797
3798                if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
3799                {
3800                    sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",tablename,tmp.datalong,tmp.id);
3801
3802                    // this will prevent quest completing without objective
3803                    const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
3804
3805                    // continue; - quest objective requiremet set and command can be allowed
3806                }
3807
3808                if(float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
3809                {
3810                    sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong2,tmp.id);
3811                    continue;
3812                }
3813
3814                if(tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
3815                {
3816                    sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %u or 0 for disable distance check",tablename,tmp.datalong2,tmp.id,uint32(DEFAULT_VISIBILITY_DISTANCE));
3817                    continue;
3818                }
3819
3820                if(tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE)
3821                {
3822                    sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %u or 0 for disable distance check",tablename,tmp.datalong2,tmp.id,uint32(INTERACTION_DISTANCE));
3823                    continue;
3824                }
3825
3826                break;
3827            }
3828
3829            case SCRIPT_COMMAND_REMOVE_AURA:
3830            case SCRIPT_COMMAND_CAST_SPELL:
3831            {
3832                if(!sSpellStore.LookupEntry(tmp.datalong))
3833                {
3834                    sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u",tablename,tmp.datalong,tmp.id);
3835                    continue;
3836                }
3837                break;
3838            }
3839        }
3840
3841        if (scripts.find(tmp.id) == scripts.end())
3842        {
3843            ScriptMap emptyMap;
3844            scripts[tmp.id] = emptyMap;
3845        }
3846        scripts[tmp.id].insert(std::pair<uint32, ScriptInfo>(tmp.delay, tmp));
3847
3848        ++count;
3849    } while( result->NextRow() );
3850
3851    delete result;
3852
3853    sLog.outString();
3854    sLog.outString( ">> Loaded %u script definitions", count );
3855}
3856
3857void ObjectMgr::LoadGameObjectScripts()
3858{
3859    LoadScripts(sGameObjectScripts,    "gameobject_scripts");
3860
3861    // check ids
3862    for(ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr)
3863    {
3864        if(!GetGOData(itr->first))
3865            sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id",itr->first);
3866    }
3867}
3868
3869void ObjectMgr::LoadQuestEndScripts()
3870{
3871    LoadScripts(sQuestEndScripts,  "quest_end_scripts");
3872
3873    // check ids
3874    for(ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr)
3875    {
3876        if(!GetQuestTemplate(itr->first))
3877            sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id",itr->first);
3878    }
3879}
3880
3881void ObjectMgr::LoadQuestStartScripts()
3882{
3883    LoadScripts(sQuestStartScripts,"quest_start_scripts");
3884
3885    // check ids
3886    for(ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr)
3887    {
3888        if(!GetQuestTemplate(itr->first))
3889            sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id",itr->first);
3890    }
3891}
3892
3893void ObjectMgr::LoadSpellScripts()
3894{
3895    LoadScripts(sSpellScripts, "spell_scripts");
3896
3897    // check ids
3898    for(ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr)
3899    {
3900        SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
3901
3902        if(!spellInfo)
3903        {
3904            sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id",itr->first);
3905            continue;
3906        }
3907
3908        //check for correct spellEffect
3909        bool found = false;
3910        for(int i=0; i<3; ++i)
3911        {
3912            // skip empty effects
3913            if( !spellInfo->Effect[i] )
3914                continue;
3915
3916            if( spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT )
3917            {
3918                found =  true;
3919                break;
3920            }
3921        }
3922
3923        if(!found)
3924            sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect",itr->first,SPELL_EFFECT_SCRIPT_EFFECT);
3925    }
3926}
3927
3928void ObjectMgr::LoadEventScripts()
3929{
3930    LoadScripts(sEventScripts, "event_scripts");
3931
3932    std::set<uint32> evt_scripts;
3933    // Load all possible script entries from gameobjects
3934    for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
3935    {
3936        GameObjectInfo const * goInfo = sGOStorage.LookupEntry<GameObjectInfo>(i);
3937        if (goInfo)
3938        {
3939            switch(goInfo->type)
3940            {
3941                case GAMEOBJECT_TYPE_GOOBER:
3942                    if(goInfo->goober.eventId)
3943                        evt_scripts.insert(goInfo->goober.eventId);
3944                    break;
3945                case GAMEOBJECT_TYPE_CHEST:
3946                    if(goInfo->chest.eventId)
3947                        evt_scripts.insert(goInfo->chest.eventId);
3948                    break;
3949                default:
3950                    break;
3951            }
3952        }
3953    }
3954    // Load all possible script entries from spells
3955    for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
3956    {
3957        SpellEntry const * spell = sSpellStore.LookupEntry(i);
3958        if (spell)
3959        {
3960            for(int j=0; j<3; ++j)
3961            {
3962                if( spell->Effect[j] == SPELL_EFFECT_SEND_EVENT )
3963                {
3964                    if (spell->EffectMiscValue[j])
3965                        evt_scripts.insert(spell->EffectMiscValue[j]);
3966                }
3967            }
3968        }
3969    }
3970    // Then check if all scripts are in above list of possible script entries
3971    for(ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr)
3972    {
3973        std::set<uint32>::const_iterator itr2 = evt_scripts.find(itr->first);
3974        if (itr2 == evt_scripts.end())
3975            sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not refering to any gameobject_template type 10 data2 field or type 3 data6 field or any spell effect %u", itr->first, SPELL_EFFECT_SEND_EVENT);
3976    }
3977}
3978
3979void ObjectMgr::LoadItemTexts()
3980{
3981    QueryResult *result = CharacterDatabase.PQuery("SELECT id, text FROM item_text");
3982
3983    uint32 count = 0;
3984
3985    if( !result )
3986    {
3987        barGoLink bar( 1 );
3988        bar.step();
3989
3990        sLog.outString();
3991        sLog.outString( ">> Loaded %u item pages", count );
3992        return;
3993    }
3994
3995    barGoLink bar( result->GetRowCount() );
3996
3997    Field* fields;
3998    do
3999    {
4000        bar.step();
4001
4002        fields = result->Fetch();
4003
4004        mItemTexts[ fields[0].GetUInt32() ] = fields[1].GetCppString();
4005
4006        ++count;
4007
4008    } while ( result->NextRow() );
4009
4010    delete result;
4011
4012    sLog.outString();
4013    sLog.outString( ">> Loaded %u item texts", count );
4014}
4015
4016void ObjectMgr::LoadPageTexts()
4017{
4018    sPageTextStore.Free();                                  // for reload case
4019
4020    sPageTextStore.Load();
4021    sLog.outString( ">> Loaded %u page texts", sPageTextStore.RecordCount );
4022    sLog.outString();
4023
4024    for(uint32 i = 1; i < sPageTextStore.MaxEntry; ++i)
4025    {
4026        // check data correctness
4027        PageText const* page = sPageTextStore.LookupEntry<PageText>(i);
4028        if(!page)
4029            continue;
4030
4031        if(page->Next_Page && !sPageTextStore.LookupEntry<PageText>(page->Next_Page))
4032        {
4033            sLog.outErrorDb("Page text (Id: %u) has not existing next page (Id:%u)", i,page->Next_Page);
4034            continue;
4035        }
4036
4037        // detect circular reference
4038        std::set<uint32> checkedPages;
4039        for(PageText const* pageItr = page; pageItr; pageItr = sPageTextStore.LookupEntry<PageText>(pageItr->Next_Page))
4040        {
4041            if(!pageItr->Next_Page)
4042                break;
4043            checkedPages.insert(pageItr->Page_ID);
4044            if(checkedPages.find(pageItr->Next_Page)!=checkedPages.end())
4045            {
4046                std::ostringstream ss;
4047                ss<< "The text page(s) ";
4048                for (std::set<uint32>::iterator itr= checkedPages.begin();itr!=checkedPages.end(); itr++)
4049                    ss << *itr << " ";
4050                ss << "create(s) a circular reference, which can cause the server to freeze. Changing Next_Page of page "
4051                    << pageItr->Page_ID <<" to 0";
4052                sLog.outErrorDb(ss.str().c_str());
4053                const_cast<PageText*>(pageItr)->Next_Page = 0;
4054                break;
4055            }
4056        }
4057    }
4058}
4059
4060void ObjectMgr::LoadPageTextLocales()
4061{
4062    mPageTextLocaleMap.clear();
4063   
4064    QueryResult *result = WorldDatabase.PQuery("SELECT entry,text_loc1,text_loc2,text_loc3,text_loc4,text_loc5,text_loc6,text_loc7,text_loc8 FROM locales_page_text");
4065
4066    if(!result)
4067    {
4068        barGoLink bar(1);
4069
4070        bar.step();
4071
4072        sLog.outString("");
4073        sLog.outString(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty.");
4074        return;
4075    }
4076
4077    barGoLink bar(result->GetRowCount());
4078
4079    do
4080    {
4081        Field *fields = result->Fetch();
4082        bar.step();
4083
4084        uint32 entry = fields[0].GetUInt32();
4085
4086        PageTextLocale& data = mPageTextLocaleMap[entry];
4087
4088        for(int i = 1; i < MAX_LOCALE; ++i)
4089        {
4090            std::string str = fields[i].GetCppString();
4091            if(str.empty())
4092                continue;
4093
4094            int idx = GetOrNewIndexForLocale(LocaleConstant(i));
4095            if(idx >= 0)
4096            {
4097                if(data.Text.size() <= idx)
4098                    data.Text.resize(idx+1);
4099
4100                data.Text[idx] = str;
4101            }
4102        }
4103
4104    } while (result->NextRow());
4105
4106    delete result;
4107
4108    sLog.outString();
4109    sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() );
4110}
4111
4112void ObjectMgr::LoadInstanceTemplate()
4113{
4114    sInstanceTemplate.Load();
4115
4116    for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++)
4117    {
4118        InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i);
4119        if(!temp) continue;
4120        const MapEntry* entry = sMapStore.LookupEntry(temp->map);
4121        if(!entry)
4122        {
4123            sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map);
4124            continue;
4125        }
4126        else if(!entry->HasResetTime())
4127            continue;
4128
4129        if(temp->reset_delay == 0)
4130        {
4131            // use defaults from the DBC
4132            if(entry->SupportsHeroicMode())
4133            {
4134                temp->reset_delay = entry->resetTimeHeroic / DAY;
4135            }
4136            else if (entry->resetTimeRaid && entry->map_type == MAP_RAID)
4137            {
4138                temp->reset_delay = entry->resetTimeRaid / DAY;
4139            }
4140        }
4141
4142        // the reset_delay must be atleast one day
4143        temp->reset_delay = std::max((uint32)1, (uint32)(temp->reset_delay * sWorld.getRate(RATE_INSTANCE_RESET_TIME)));
4144    }
4145
4146    sLog.outString( ">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount );
4147    sLog.outString();
4148}
4149
4150void ObjectMgr::AddGossipText(GossipText *pGText)
4151{
4152    ASSERT( pGText->Text_ID );
4153    ASSERT( mGossipText.find(pGText->Text_ID) == mGossipText.end() );
4154    mGossipText[pGText->Text_ID] = pGText;
4155}
4156
4157GossipText *ObjectMgr::GetGossipText(uint32 Text_ID)
4158{
4159    GossipTextMap::const_iterator itr;
4160    for (itr = mGossipText.begin(); itr != mGossipText.end(); itr++)
4161    {
4162        if(itr->second->Text_ID == Text_ID)
4163            return itr->second;
4164    }
4165    return NULL;
4166}
4167
4168void ObjectMgr::LoadGossipText()
4169{
4170    GossipText *pGText;
4171    QueryResult *result = WorldDatabase.Query( "SELECT * FROM npc_text" );
4172
4173    int count = 0;
4174    if( !result )
4175    {
4176        barGoLink bar( 1 );
4177        bar.step();
4178
4179        sLog.outString();
4180        sLog.outString( ">> Loaded %u npc texts", count );
4181        return;
4182    }
4183
4184    int cic;
4185
4186    barGoLink bar( result->GetRowCount() );
4187
4188    do
4189    {
4190        ++count;
4191        cic = 0;
4192
4193        Field *fields = result->Fetch();
4194
4195        bar.step();
4196
4197        pGText = new GossipText;
4198        pGText->Text_ID    = fields[cic++].GetUInt32();
4199
4200        for (int i=0; i< 8; i++)
4201        {
4202            pGText->Options[i].Text_0           = fields[cic++].GetCppString();
4203            pGText->Options[i].Text_1           = fields[cic++].GetCppString();
4204
4205            pGText->Options[i].Language         = fields[cic++].GetUInt32();
4206            pGText->Options[i].Probability      = fields[cic++].GetFloat();
4207
4208            pGText->Options[i].Emotes[0]._Delay  = fields[cic++].GetUInt32();
4209            pGText->Options[i].Emotes[0]._Emote  = fields[cic++].GetUInt32();
4210
4211            pGText->Options[i].Emotes[1]._Delay  = fields[cic++].GetUInt32();
4212            pGText->Options[i].Emotes[1]._Emote  = fields[cic++].GetUInt32();
4213
4214            pGText->Options[i].Emotes[2]._Delay  = fields[cic++].GetUInt32();
4215            pGText->Options[i].Emotes[2]._Emote  = fields[cic++].GetUInt32();
4216        }
4217
4218        if ( !pGText->Text_ID ) continue;
4219        AddGossipText( pGText );
4220
4221    } while( result->NextRow() );
4222
4223    sLog.outString();
4224    sLog.outString( ">> Loaded %u npc texts", count );
4225    delete result;
4226}
4227
4228void ObjectMgr::LoadNpcTextLocales()
4229{
4230    mNpcTextLocaleMap.clear();
4231   
4232    QueryResult *result = WorldDatabase.Query("SELECT entry,"
4233        "Text0_0_loc1,Text0_1_loc1,Text1_0_loc1,Text1_1_loc1,Text2_0_loc1,Text2_1_loc1,Text3_0_loc1,Text3_1_loc1,Text4_0_loc1,Text4_1_loc1,Text5_0_loc1,Text5_1_loc1,Text6_0_loc1,Text6_1_loc1,Text7_0_loc1,Text7_1_loc1,"
4234        "Text0_0_loc2,Text0_1_loc2,Text1_0_loc2,Text1_1_loc2,Text2_0_loc2,Text2_1_loc2,Text3_0_loc2,Text3_1_loc1,Text4_0_loc2,Text4_1_loc2,Text5_0_loc2,Text5_1_loc2,Text6_0_loc2,Text6_1_loc2,Text7_0_loc2,Text7_1_loc2,"
4235        "Text0_0_loc3,Text0_1_loc3,Text1_0_loc3,Text1_1_loc3,Text2_0_loc3,Text2_1_loc3,Text3_0_loc3,Text3_1_loc1,Text4_0_loc3,Text4_1_loc3,Text5_0_loc3,Text5_1_loc3,Text6_0_loc3,Text6_1_loc3,Text7_0_loc3,Text7_1_loc3,"
4236        "Text0_0_loc4,Text0_1_loc4,Text1_0_loc4,Text1_1_loc4,Text2_0_loc4,Text2_1_loc4,Text3_0_loc4,Text3_1_loc1,Text4_0_loc4,Text4_1_loc4,Text5_0_loc4,Text5_1_loc4,Text6_0_loc4,Text6_1_loc4,Text7_0_loc4,Text7_1_loc4,"
4237        "Text0_0_loc5,Text0_1_loc5,Text1_0_loc5,Text1_1_loc5,Text2_0_loc5,Text2_1_loc5,Text3_0_loc5,Text3_1_loc1,Text4_0_loc5,Text4_1_loc5,Text5_0_loc5,Text5_1_loc5,Text6_0_loc5,Text6_1_loc5,Text7_0_loc5,Text7_1_loc5,"
4238        "Text0_0_loc6,Text0_1_loc6,Text1_0_loc6,Text1_1_loc6,Text2_0_loc6,Text2_1_loc6,Text3_0_loc6,Text3_1_loc1,Text4_0_loc6,Text4_1_loc6,Text5_0_loc6,Text5_1_loc6,Text6_0_loc6,Text6_1_loc6,Text7_0_loc6,Text7_1_loc6,"
4239        "Text0_0_loc7,Text0_1_loc7,Text1_0_loc7,Text1_1_loc7,Text2_0_loc7,Text2_1_loc7,Text3_0_loc7,Text3_1_loc1,Text4_0_loc7,Text4_1_loc7,Text5_0_loc7,Text5_1_loc7,Text6_0_loc7,Text6_1_loc7,Text7_0_loc7,Text7_1_loc7, "
4240        "Text0_0_loc8,Text0_1_loc8,Text1_0_loc8,Text1_1_loc8,Text2_0_loc8,Text2_1_loc8,Text3_0_loc8,Text3_1_loc1,Text4_0_loc8,Text4_1_loc8,Text5_0_loc8,Text5_1_loc8,Text6_0_loc8,Text6_1_loc8,Text7_0_loc8,Text7_1_loc8 "
4241        " FROM locales_npc_text");
4242
4243    if(!result)
4244    {
4245        barGoLink bar(1);
4246
4247        bar.step();
4248
4249        sLog.outString("");
4250        sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty.");
4251        return;
4252    }
4253
4254    barGoLink bar(result->GetRowCount());
4255
4256    do
4257    {
4258        Field *fields = result->Fetch();
4259        bar.step();
4260
4261        uint32 entry = fields[0].GetUInt32();
4262
4263        NpcTextLocale& data = mNpcTextLocaleMap[entry];
4264
4265        for(int i=1; i<MAX_LOCALE; ++i)
4266        {
4267            for(int j=0; j<8; ++j)
4268            {
4269                std::string str0 = fields[1+8*2*(i-1)+2*j].GetCppString();
4270                if(!str0.empty())
4271                {
4272                    int idx = GetOrNewIndexForLocale(LocaleConstant(i));
4273                    if(idx >= 0)
4274                    {
4275                        if(data.Text_0[j].size() <= idx)
4276                            data.Text_0[j].resize(idx+1);
4277
4278                        data.Text_0[j][idx] = str0;
4279                    }
4280                }
4281                std::string str1 = fields[1+8*2*(i-1)+2*j+1].GetCppString();
4282                if(!str1.empty())
4283                {
4284                    int idx = GetOrNewIndexForLocale(LocaleConstant(i));
4285                    if(idx >= 0)
4286                    {
4287                        if(data.Text_1[j].size() <= idx)
4288                            data.Text_1[j].resize(idx+1);
4289
4290                        data.Text_1[j][idx] = str1;
4291                    }
4292                }
4293            }
4294        }
4295    } while (result->NextRow());
4296
4297    delete result;
4298
4299    sLog.outString();
4300    sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() );
4301}
4302
4303//not very fast function but it is called only once a day, or on starting-up
4304void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
4305{
4306    time_t basetime = time(NULL);
4307    sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec);
4308    //delete all old mails without item and without body immediately, if starting server
4309    if (!serverUp)
4310        CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" I64FMTD "' AND has_items = '0' AND itemTextId = 0", (uint64)basetime);
4311    //                                                     0  1           2      3        4          5         6           7   8       9
4312    QueryResult* result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,itemTextId,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" I64FMTD "'", (uint64)basetime);
4313    if ( !result )
4314        return;                                             // any mails need to be returned or deleted
4315    Field *fields;
4316    //std::ostringstream delitems, delmails; //will be here for optimization
4317    //bool deletemail = false, deleteitem = false;
4318    //delitems << "DELETE FROM item_instance WHERE guid IN ( ";
4319    //delmails << "DELETE FROM mail WHERE id IN ( "
4320    do
4321    {
4322        fields = result->Fetch();
4323        Mail *m = new Mail;
4324        m->messageID = fields[0].GetUInt32();
4325        m->messageType = fields[1].GetUInt8();
4326        m->sender = fields[2].GetUInt32();
4327        m->receiver = fields[3].GetUInt32();
4328        m->itemTextId = fields[4].GetUInt32();
4329        bool has_items = fields[5].GetBool();
4330        m->expire_time = (time_t)fields[6].GetUInt64();
4331        m->deliver_time = 0;
4332        m->COD = fields[7].GetUInt32();
4333        m->checked = fields[8].GetUInt32();
4334        m->mailTemplateId = fields[9].GetInt16();
4335
4336        Player *pl = 0;
4337        if (serverUp)
4338            pl = GetPlayer((uint64)m->receiver);
4339        if (pl && pl->m_mailsLoaded)
4340        {                                                   //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail
4341            //his in mailbox and he has already listed his mails )
4342            delete m;
4343            continue;
4344        }
4345        //delete or return mail:
4346        if (has_items)
4347        {
4348            QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", m->messageID);
4349            if(resultItems)
4350            {
4351                do
4352                {
4353                    Field *fields2 = resultItems->Fetch();
4354
4355                    uint32 item_guid_low = fields2[0].GetUInt32();
4356                    uint32 item_template = fields2[1].GetUInt32();
4357
4358                    m->AddItem(item_guid_low, item_template);
4359                }
4360                while (resultItems->NextRow());
4361
4362                delete resultItems;
4363            }
4364            //if it is mail from AH, it shouldn't be returned, but deleted
4365            if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_AUCTION | MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED)))
4366            {
4367                // mail open and then not returned
4368                for(std::vector<MailItemInfo>::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
4369                    CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid);
4370            }
4371            else
4372            {
4373                //mail will be returned:
4374                CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" I64FMTD "', deliver_time = '" I64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID);
4375                delete m;
4376                continue;
4377            }
4378        }
4379
4380        if (m->itemTextId)
4381            CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId);
4382
4383        //deletemail = true;
4384        //delmails << m->messageID << ", ";
4385        CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID);
4386        delete m;
4387    } while (result->NextRow());
4388    delete result;
4389}
4390
4391void ObjectMgr::LoadQuestAreaTriggers()
4392{
4393    mQuestAreaTriggerMap.clear();                           // need for reload case
4394
4395    QueryResult *result = WorldDatabase.Query( "SELECT id,quest FROM areatrigger_involvedrelation" );
4396
4397    uint32 count = 0;
4398
4399    if( !result )
4400    {
4401        barGoLink bar( 1 );
4402        bar.step();
4403
4404        sLog.outString();
4405        sLog.outString( ">> Loaded %u quest trigger points", count );
4406        return;
4407    }
4408
4409    barGoLink bar( result->GetRowCount() );
4410
4411    do
4412    {
4413        ++count;
4414        bar.step();
4415
4416        Field *fields = result->Fetch();
4417
4418        uint32 trigger_ID = fields[0].GetUInt32();
4419        uint32 quest_ID   = fields[1].GetUInt32();
4420
4421        AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID);
4422        if(!atEntry)
4423        {
4424            sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",trigger_ID);
4425            continue;
4426        }
4427
4428        Quest const* quest = GetQuestTemplate(quest_ID);
4429
4430        if(!quest)
4431        {
4432            sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u",trigger_ID,quest_ID);
4433            continue;
4434        }
4435
4436        if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
4437        {
4438            sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not quest %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.",trigger_ID,quest_ID);
4439
4440            // this will prevent quest completing without objective
4441            const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
4442
4443            // continue; - quest modified to required obkective and trigger can be allowed.
4444        }
4445
4446        mQuestAreaTriggerMap[trigger_ID] = quest_ID;
4447
4448    } while( result->NextRow() );
4449
4450    delete result;
4451
4452    sLog.outString();
4453    sLog.outString( ">> Loaded %u quest trigger points", count );
4454}
4455
4456void ObjectMgr::LoadTavernAreaTriggers()
4457{
4458    mTavernAreaTriggerSet.clear();                          // need for reload case
4459
4460    QueryResult *result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern");
4461
4462    uint32 count = 0;
4463
4464    if( !result )
4465    {
4466        barGoLink bar( 1 );
4467        bar.step();
4468
4469        sLog.outString();
4470        sLog.outString( ">> Loaded %u tavern triggers", count );
4471        return;
4472    }
4473
4474    barGoLink bar( result->GetRowCount() );
4475
4476    do
4477    {
4478        ++count;
4479        bar.step();
4480
4481        Field *fields = result->Fetch();
4482
4483        uint32 Trigger_ID      = fields[0].GetUInt32();
4484
4485        AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
4486        if(!atEntry)
4487        {
4488            sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
4489            continue;
4490        }
4491
4492        mTavernAreaTriggerSet.insert(Trigger_ID);
4493    } while( result->NextRow() );
4494
4495    delete result;
4496
4497    sLog.outString();
4498    sLog.outString( ">> Loaded %u tavern triggers", count );
4499}
4500
4501void ObjectMgr::LoadAreaTriggerScripts()
4502{
4503    mAreaTriggerScripts.clear();                            // need for reload case
4504    QueryResult *result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts");
4505
4506    uint32 count = 0;
4507
4508    if( !result )
4509    {
4510        barGoLink bar( 1 );
4511        bar.step();
4512
4513        sLog.outString();
4514        sLog.outString( ">> Loaded %u areatrigger scripts", count );
4515        return;
4516    }
4517
4518    barGoLink bar( result->GetRowCount() );
4519
4520    do
4521    {
4522        ++count;
4523        bar.step();
4524
4525        Field *fields = result->Fetch();
4526
4527        uint32 Trigger_ID      = fields[0].GetUInt32();
4528        std::string scriptName = fields[1].GetCppString();
4529
4530        AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
4531        if(!atEntry)
4532        {
4533            sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
4534            continue;
4535        }
4536        mAreaTriggerScripts[Trigger_ID] = scriptName;
4537    } while( result->NextRow() );
4538
4539    delete result;
4540
4541    sLog.outString();
4542    sLog.outString( ">> Loaded %u areatrigger scripts", count );
4543}
4544uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
4545{
4546    bool found = false;
4547    float dist;
4548    uint32 id = 0;
4549
4550    for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
4551    {
4552        TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
4553        if(node && node->map_id == mapid)
4554        {
4555            float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z);
4556            if(found)
4557            {
4558                if(dist2 < dist)
4559                {
4560                    dist = dist2;
4561                    id = i;
4562                }
4563            }
4564            else
4565            {
4566                found = true;
4567                dist = dist2;
4568                id = i;
4569            }
4570        }
4571    }
4572
4573    return id;
4574}
4575
4576void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost)
4577{
4578    TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source);
4579    if(src_i==sTaxiPathSetBySource.end())
4580    {
4581        path = 0;
4582        cost = 0;
4583        return;
4584    }
4585
4586    TaxiPathSetForSource& pathSet = src_i->second;
4587
4588    TaxiPathSetForSource::iterator dest_i = pathSet.find(destination);
4589    if(dest_i==pathSet.end())
4590    {
4591        path = 0;
4592        cost = 0;
4593        return;
4594    }
4595
4596    cost = dest_i->second.price;
4597    path = dest_i->second.ID;
4598}
4599
4600uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
4601{
4602    uint16 mount_entry = 0;
4603    uint16 mount_id = 0;
4604
4605    TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id);
4606    if(node)
4607    {
4608        if (team == ALLIANCE)
4609        {
4610            mount_entry = node->alliance_mount_type;
4611            CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
4612            if(ci)
4613                mount_id = ci->DisplayID_A;
4614        }
4615        if (team == HORDE)
4616        {
4617            mount_entry = node->horde_mount_type;
4618            CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
4619            if(ci)
4620                mount_id = ci->DisplayID_H;
4621        }
4622    }
4623
4624    CreatureModelInfo const *minfo = GetCreatureModelInfo(mount_id);
4625    if(!minfo)
4626    {
4627        sLog.outErrorDb("Taxi mount (Entry: %u) for taxi node (Id: %u) for team %u has model %u not found in table `creature_model_info`, can't load. ",
4628            mount_entry,id,team,mount_id);
4629
4630        return false;
4631    }
4632    if(minfo->modelid_other_gender!=0)
4633        mount_id = urand(0,1) ? mount_id : minfo->modelid_other_gender;
4634
4635    return mount_id;
4636}
4637
4638void ObjectMgr::GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds)
4639{
4640    if(path >= sTaxiPathNodesByPath.size())
4641        return;
4642
4643    TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path];
4644
4645    pathnodes.Resize(nodeList.size());
4646    mapIds.resize(nodeList.size());
4647
4648    for(size_t i = 0; i < nodeList.size(); ++i)
4649    {
4650        pathnodes[ i ].x = nodeList[i].x;
4651        pathnodes[ i ].y = nodeList[i].y;
4652        pathnodes[ i ].z = nodeList[i].z;
4653
4654        mapIds[i] = nodeList[i].mapid;
4655    }
4656}
4657
4658void ObjectMgr::GetTransportPathNodes( uint32 path, TransportPath &pathnodes )
4659{
4660    if(path >= sTaxiPathNodesByPath.size())
4661        return;
4662
4663    TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path];
4664
4665    pathnodes.Resize(nodeList.size());
4666
4667    for(size_t i = 0; i < nodeList.size(); ++i)
4668    {
4669        pathnodes[ i ].mapid = nodeList[i].mapid;
4670        pathnodes[ i ].x = nodeList[i].x;
4671        pathnodes[ i ].y = nodeList[i].y;
4672        pathnodes[ i ].z = nodeList[i].z;
4673        pathnodes[ i ].actionFlag = nodeList[i].actionFlag;
4674        pathnodes[ i ].delay = nodeList[i].delay;
4675    }
4676}
4677
4678void ObjectMgr::LoadGraveyardZones()
4679{
4680    mGraveYardMap.clear();                                  // need for reload case
4681
4682    QueryResult *result = WorldDatabase.Query("SELECT id,ghost_zone,faction FROM game_graveyard_zone");
4683
4684    uint32 count = 0;
4685
4686    if( !result )
4687    {
4688        barGoLink bar( 1 );
4689        bar.step();
4690
4691        sLog.outString();
4692        sLog.outString( ">> Loaded %u graveyard-zone links", count );
4693        return;
4694    }
4695
4696    barGoLink bar( result->GetRowCount() );
4697
4698    do
4699    {
4700        ++count;
4701        bar.step();
4702
4703        Field *fields = result->Fetch();
4704
4705        uint32 safeLocId = fields[0].GetUInt32();
4706        uint32 zoneId = fields[1].GetUInt32();
4707        uint32 team   = fields[2].GetUInt32();
4708
4709        WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId);
4710        if(!entry)
4711        {
4712            sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",safeLocId);
4713            continue;
4714        }
4715
4716        AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId);
4717        if(!areaEntry)
4718        {
4719            sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing zone id (%u), skipped.",zoneId);
4720            continue;
4721        }
4722
4723        if(areaEntry->zone != 0)
4724        {
4725            sLog.outErrorDb("Table `game_graveyard_zone` has record subzone id (%u) instead of zone, skipped.",zoneId);
4726            continue;
4727        }
4728
4729        if(team!=0 && team!=HORDE && team!=ALLIANCE)
4730        {
4731            sLog.outErrorDb("Table `game_graveyard_zone` has record for non player faction (%u), skipped.",team);
4732            continue;
4733        }
4734
4735        if(entry->map_id != areaEntry->mapid && team != 0)
4736        {
4737            sLog.outErrorDb("Table `game_graveyard_zone` has record for ghost zone (%u) at map %u and graveyard (%u) at map %u for team %u, but in case maps are different, player faction setting is ignored. Use faction 0 instead.",zoneId,areaEntry->mapid, safeLocId, entry->map_id, team);
4738            team = 0;
4739        }
4740
4741        if(!AddGraveYardLink(safeLocId,zoneId,team,false))
4742            sLog.outErrorDb("Table `game_graveyard_zone` has a duplicate record for Garveyard (ID: %u) and Zone (ID: %u), skipped.",safeLocId,zoneId);
4743    } while( result->NextRow() );
4744
4745    delete result;
4746
4747    sLog.outString();
4748    sLog.outString( ">> Loaded %u graveyard-zone links", count );
4749}
4750
4751WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team)
4752{
4753    // search for zone associated closest graveyard
4754    uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y);
4755
4756    // Simulate std. algorithm:
4757    //   found some graveyard associated to (ghost_zone,ghost_map)
4758    //
4759    //   if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map
4760    //     then check faction
4761    //   if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated
4762    //     then skip check faction
4763    GraveYardMap::const_iterator graveLow  = mGraveYardMap.lower_bound(zoneId);
4764    GraveYardMap::const_iterator graveUp   = mGraveYardMap.upper_bound(zoneId);
4765    if(graveLow==graveUp)
4766    {
4767        sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
4768        return NULL;
4769    }
4770
4771    bool foundNear = false;
4772    float distNear;
4773    WorldSafeLocsEntry const* entryNear = NULL;
4774    WorldSafeLocsEntry const* entryFar = NULL;
4775
4776    for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr)
4777    {
4778        GraveYardData const& data = itr->second;
4779
4780        WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId);
4781        if(!entry)
4782        {
4783            sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",data.safeLocId);
4784            continue;
4785        }
4786
4787        // remember first graveyard at another map and ignore other
4788        if(MapId != entry->map_id)
4789        {
4790            if(!entryFar)
4791                entryFar = entry;
4792            continue;
4793        }
4794
4795        // skip enemy faction graveyard at same map (normal area, city, or battleground)
4796        // team == 0 case can be at call from .neargrave
4797        if(data.team != 0 && team != 0 && data.team != team)
4798            continue;
4799
4800        // find now nearest graveyard at same map
4801        float dist2 = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y)+(entry->z - z)*(entry->z - z);
4802        if(foundNear)
4803        {
4804            if(dist2 < distNear)
4805            {
4806                distNear = dist2;
4807                entryNear = entry;
4808            }
4809        }
4810        else
4811        {
4812            foundNear = true;
4813            distNear = dist2;
4814            entryNear = entry;
4815        }
4816    }
4817
4818    if(entryNear)
4819        return entryNear;
4820
4821    return entryFar;
4822}
4823
4824GraveYardData const* ObjectMgr::FindGraveYardData(uint32 id, uint32 zoneId)
4825{
4826    GraveYardMap::const_iterator graveLow  = mGraveYardMap.lower_bound(zoneId);
4827    GraveYardMap::const_iterator graveUp   = mGraveYardMap.upper_bound(zoneId);
4828
4829    for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr)
4830    {
4831        if(itr->second.safeLocId==id)
4832            return &itr->second;
4833    }
4834
4835    return NULL;
4836}
4837
4838bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB)
4839{
4840    if(FindGraveYardData(id,zoneId))
4841        return false;
4842
4843    // add link to loaded data
4844    GraveYardData data;
4845    data.safeLocId = id;
4846    data.team = team;
4847
4848    mGraveYardMap.insert(GraveYardMap::value_type(zoneId,data));
4849
4850    // add link to DB
4851    if(inDB)
4852    {
4853        WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone ( id,ghost_zone,faction) "
4854            "VALUES ('%u', '%u','%u')",id,zoneId,team);
4855    }
4856
4857    return true;
4858}
4859
4860void ObjectMgr::RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB)
4861{
4862    GraveYardMap::iterator graveLow  = mGraveYardMap.lower_bound(zoneId);
4863    GraveYardMap::iterator graveUp   = mGraveYardMap.upper_bound(zoneId);
4864    if(graveLow==graveUp)
4865    {
4866        //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
4867        return;
4868    }
4869
4870    bool found = false;
4871
4872    GraveYardMap::iterator itr;
4873
4874    for(itr = graveLow; itr != graveUp; ++itr)
4875    {
4876        GraveYardData & data = itr->second;
4877
4878        // skip not matching safezone id
4879        if(data.safeLocId != id)
4880            continue;
4881
4882        // skip enemy faction graveyard at same map (normal area, city, or battleground)
4883        // team == 0 case can be at call from .neargrave
4884        if(data.team != 0 && team != 0 && data.team != team)
4885            continue;
4886
4887        found = true;
4888        break;
4889    }
4890
4891    // no match, return
4892    if(!found)
4893        return;
4894
4895    // remove from links
4896    mGraveYardMap.erase(itr);
4897
4898    // remove link from DB
4899    if(inDB)
4900    {
4901        WorldDatabase.PExecute("DELETE FROM game_graveyard_zone WHERE id = '%u' AND ghost_zone = '%u' AND faction = '%u'",id,zoneId,team);
4902    }
4903
4904    return;
4905}
4906
4907
4908void ObjectMgr::LoadAreaTriggerTeleports()
4909{
4910    mAreaTriggers.clear();                                  // need for reload case
4911
4912    uint32 count = 0;
4913
4914    //                                                0   1               2              3               4           5            6                    7                     8           9                  10                 11                 12
4915    QueryResult *result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
4916    if( !result )
4917    {
4918
4919        barGoLink bar( 1 );
4920
4921        bar.step();
4922
4923        sLog.outString();
4924        sLog.outString( ">> Loaded %u area trigger teleport definitions", count );
4925        return;
4926    }
4927
4928    barGoLink bar( result->GetRowCount() );
4929
4930    do
4931    {
4932        Field *fields = result->Fetch();
4933
4934        bar.step();
4935
4936        ++count;
4937
4938        uint32 Trigger_ID = fields[0].GetUInt32();
4939
4940        AreaTrigger at;
4941
4942        at.requiredLevel      = fields[1].GetUInt8();
4943        at.requiredItem       = fields[2].GetUInt32();
4944        at.requiredItem2      = fields[3].GetUInt32();
4945        at.heroicKey          = fields[4].GetUInt32();
4946        at.heroicKey2         = fields[5].GetUInt32();
4947        at.requiredQuest      = fields[6].GetUInt32();
4948        at.requiredFailedText = fields[7].GetCppString();
4949        at.target_mapId       = fields[8].GetUInt32();
4950        at.target_X           = fields[9].GetFloat();
4951        at.target_Y           = fields[10].GetFloat();
4952        at.target_Z           = fields[11].GetFloat();
4953        at.target_Orientation = fields[12].GetFloat();
4954
4955        AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
4956        if(!atEntry)
4957        {
4958            sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
4959            continue;
4960        }
4961
4962        if(at.requiredItem)
4963        {
4964            ItemPrototype const *pProto = GetItemPrototype(at.requiredItem);
4965            if(!pProto)
4966            {
4967                sLog.outError("Key item %u does not exist for trigger %u, removing key requirement.", at.requiredItem, Trigger_ID);
4968                at.requiredItem = 0;
4969            }
4970        }
4971        if(at.requiredItem2)
4972        {
4973            ItemPrototype const *pProto = GetItemPrototype(at.requiredItem2);
4974            if(!pProto)
4975            {
4976                sLog.outError("Second item %u not exist for trigger %u, remove key requirement.", at.requiredItem2, Trigger_ID);
4977                at.requiredItem2 = 0;
4978            }
4979        }
4980
4981        if(at.heroicKey)
4982        {
4983            ItemPrototype const *pProto = GetItemPrototype(at.heroicKey);
4984            if(!pProto)
4985            {
4986                sLog.outError("Heroic key item %u not exist for trigger %u, remove key requirement.", at.heroicKey, Trigger_ID);
4987                at.heroicKey = 0;
4988            }
4989        }
4990
4991        if(at.heroicKey2)
4992        {
4993            ItemPrototype const *pProto = GetItemPrototype(at.heroicKey2);
4994            if(!pProto)
4995            {
4996                sLog.outError("Heroic second key item %u not exist for trigger %u, remove key requirement.", at.heroicKey2, Trigger_ID);
4997                at.heroicKey2 = 0;
4998            }
4999        }
5000
5001        if(at.requiredQuest)
5002        {
5003            if(!mQuestTemplates[at.requiredQuest])
5004            {
5005                sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",at.requiredQuest,Trigger_ID);
5006                at.requiredQuest = 0;
5007            }
5008        }
5009
5010        MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId);
5011        if(!mapEntry)
5012        {
5013            sLog.outErrorDb("Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Trigger_ID,at.target_mapId);
5014            continue;
5015        }
5016
5017        if(at.target_X==0 && at.target_Y==0 && at.target_Z==0)
5018        {
5019            sLog.outErrorDb("Area trigger (ID:%u) target coordinates not provided.",Trigger_ID);
5020            continue;
5021        }
5022
5023        mAreaTriggers[Trigger_ID] = at;
5024
5025    } while( result->NextRow() );
5026
5027    delete result;
5028
5029    sLog.outString();
5030    sLog.outString( ">> Loaded %u area trigger teleport definitions", count );
5031}
5032
5033AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const
5034{
5035    const MapEntry *mapEntry = sMapStore.LookupEntry(Map);
5036    if(!mapEntry) return NULL;
5037    for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); itr++)
5038    {
5039        if(itr->second.target_mapId == mapEntry->parent_map)
5040        {
5041            AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first);
5042            if(atEntry && atEntry->mapid == Map)
5043                return &itr->second;
5044        }
5045    }
5046    return NULL;
5047}
5048
5049void ObjectMgr::SetHighestGuids()
5050{
5051    QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" );
5052    if( result )
5053    {
5054        m_hiCharGuid = (*result)[0].GetUInt32()+1;
5055
5056        delete result;
5057    }
5058
5059    result = WorldDatabase.Query( "SELECT MAX(guid) FROM creature" );
5060    if( result )
5061    {
5062        m_hiCreatureGuid = (*result)[0].GetUInt32()+1;
5063
5064        delete result;
5065    }
5066
5067    result = CharacterDatabase.Query( "SELECT MAX(id) FROM character_pet" );
5068    if( result )
5069    {
5070        m_hiPetGuid = (*result)[0].GetUInt32()+1;
5071
5072        delete result;
5073    }
5074
5075    result = CharacterDatabase.Query( "SELECT MAX(guid) FROM item_instance" );
5076    if( result )
5077    {
5078        m_hiItemGuid = (*result)[0].GetUInt32()+1;
5079
5080        delete result;
5081    }
5082
5083    // Cleanup other tables from not existed guids (>=m_hiItemGuid)
5084    CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", m_hiItemGuid);
5085    CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_hiItemGuid);
5086    CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", m_hiItemGuid);
5087    CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_hiItemGuid);
5088
5089    result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" );
5090    if( result )
5091    {
5092        m_hiGoGuid = (*result)[0].GetUInt32()+1;
5093
5094        delete result;
5095    }
5096
5097    result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse" );
5098    if( result )
5099    {
5100        m_auctionid = (*result)[0].GetUInt32()+1;
5101
5102        delete result;
5103    }
5104    else
5105    {
5106        m_auctionid = 0;
5107    }
5108    result = CharacterDatabase.Query( "SELECT MAX(id) FROM mail" );
5109    if( result )
5110    {
5111        m_mailid = (*result)[0].GetUInt32()+1;
5112
5113        delete result;
5114    }
5115    else
5116    {
5117        m_mailid = 0;
5118    }
5119    result = CharacterDatabase.Query( "SELECT MAX(id) FROM item_text" );
5120    if( result )
5121    {
5122        m_ItemTextId = (*result)[0].GetUInt32();
5123
5124        delete result;
5125    }
5126    else
5127        m_ItemTextId = 0;
5128
5129    result = CharacterDatabase.Query( "SELECT MAX(guid) FROM corpse" );
5130    if( result )
5131    {
5132        m_hiCorpseGuid = (*result)[0].GetUInt32()+1;
5133
5134        delete result;
5135    }
5136}
5137
5138uint32 ObjectMgr::GenerateAuctionID()
5139{
5140    ++m_auctionid;
5141    if(m_auctionid>=0xFFFFFFFF)
5142    {
5143        sLog.outError("Auctions ids overflow!! Can't continue, shuting down server. ");
5144        sWorld.m_stopEvent = true;
5145    }
5146    return m_auctionid;
5147}
5148
5149uint32 ObjectMgr::GenerateMailID()
5150{
5151    ++m_mailid;
5152    if(m_mailid>=0xFFFFFFFF)
5153    {
5154        sLog.outError("Mail ids overflow!! Can't continue, shuting down server. ");
5155        sWorld.m_stopEvent = true;
5156    }
5157    return m_mailid;
5158}
5159
5160uint32 ObjectMgr::GenerateItemTextID()
5161{
5162    ++m_ItemTextId;
5163    if(m_ItemTextId>=0xFFFFFFFF)
5164    {
5165        sLog.outError("Item text ids overflow!! Can't continue, shuting down server. ");
5166        sWorld.m_stopEvent = true;
5167    }
5168    return m_ItemTextId;
5169}
5170
5171uint32 ObjectMgr::CreateItemText(std::string text)
5172{
5173    uint32 newItemTextId = GenerateItemTextID();
5174    //insert new itempage to container
5175    mItemTexts[ newItemTextId ] = text;
5176    //save new itempage
5177    CharacterDatabase.escape_string(text);
5178    //any Delete query needed, itemTextId is maximum of all ids
5179    std::ostringstream query;
5180    query << "INSERT INTO item_text (id,text) VALUES ( '" << newItemTextId << "', '" << text << "')";
5181    CharacterDatabase.Execute(query.str().c_str());         //needs to be run this way, because mail body may be more than 1024 characters
5182    return newItemTextId;
5183}
5184
5185uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh)
5186{
5187    switch(guidhigh)
5188    {
5189        case HIGHGUID_ITEM:
5190            ++m_hiItemGuid;
5191            if(m_hiItemGuid>=0xFFFFFFFF)
5192            {
5193                sLog.outError("Item guid overflow!! Can't continue, shuting down server. ");
5194                sWorld.m_stopEvent = true;
5195            }
5196            return m_hiItemGuid;
5197        case HIGHGUID_UNIT:
5198            ++m_hiCreatureGuid;
5199            if(m_hiCreatureGuid>=0x00FFFFFF)
5200            {
5201                sLog.outError("Creature guid overflow!! Can't continue, shuting down server. ");
5202                sWorld.m_stopEvent = true;
5203            }
5204            return m_hiCreatureGuid;
5205        case HIGHGUID_PET:
5206            ++m_hiPetGuid;
5207            if(m_hiPetGuid>=0x00FFFFFF)
5208            {
5209                sLog.outError("Pet guid overflow!! Can't continue, shuting down server. ");
5210                sWorld.m_stopEvent = true;
5211            }
5212            return m_hiPetGuid;
5213        case HIGHGUID_PLAYER:
5214            ++m_hiCharGuid;
5215            if(m_hiCharGuid>=0xFFFFFFFF)
5216            {
5217                sLog.outError("Players guid overflow!! Can't continue, shuting down server. ");
5218                sWorld.m_stopEvent = true;
5219            }
5220            return m_hiCharGuid;
5221        case HIGHGUID_GAMEOBJECT:
5222            ++m_hiGoGuid;
5223            if(m_hiGoGuid>=0x00FFFFFF)
5224            {
5225                sLog.outError("Gameobject guid overflow!! Can't continue, shuting down server. ");
5226                sWorld.m_stopEvent = true;
5227            }
5228            return m_hiGoGuid;
5229        case HIGHGUID_CORPSE:
5230            ++m_hiCorpseGuid;
5231            if(m_hiCorpseGuid>=0xFFFFFFFF)
5232            {
5233                sLog.outError("Corpse guid overflow!! Can't continue, shuting down server. ");
5234                sWorld.m_stopEvent = true;
5235            }
5236            return m_hiCorpseGuid;
5237        case HIGHGUID_DYNAMICOBJECT:
5238            ++m_hiDoGuid;
5239            if(m_hiDoGuid>=0xFFFFFFFF)
5240            {
5241                sLog.outError("DynamicObject guid overflow!! Can't continue, shuting down server. ");
5242                sWorld.m_stopEvent = true;
5243            }
5244            return m_hiDoGuid;
5245        default:
5246            ASSERT(0);
5247    }
5248
5249    ASSERT(0);
5250    return 0;
5251}
5252
5253void ObjectMgr::LoadGameObjectLocales()
5254{
5255    mGameObjectLocaleMap.clear();
5256   
5257    QueryResult *result = WorldDatabase.Query("SELECT entry,"
5258        "name_loc1,name_loc2,name_loc3,name_loc4,name_loc5,name_loc6,name_loc7,name_loc8,"
5259        "castbarcaption_loc1,castbarcaption_loc2,castbarcaption_loc3,castbarcaption_loc4,"
5260        "castbarcaption_loc5,castbarcaption_loc6,castbarcaption_loc7,castbarcaption_loc8 FROM locales_gameobject");
5261
5262    if(!result)
5263    {
5264        barGoLink bar(1);
5265
5266        bar.step();
5267
5268        sLog.outString("");
5269        sLog.outString(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty.");
5270        return;
5271    }
5272
5273    barGoLink bar(result->GetRowCount());
5274
5275    do
5276    {
5277        Field *fields = result->Fetch();
5278        bar.step();
5279
5280        uint32 entry = fields[0].GetUInt32();
5281
5282        GameObjectLocale& data = mGameObjectLocaleMap[entry];
5283
5284        for(int i = 1; i < MAX_LOCALE; ++i)
5285        {
5286            std::string str = fields[i].GetCppString();
5287            if(!str.empty())
5288            {
5289                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
5290                if(idx >= 0)
5291                {
5292                    if(data.Name.size() <= idx)
5293                        data.Name.resize(idx+1);
5294
5295                    data.Name[idx] = str;
5296                }
5297            }
5298        }
5299
5300        for(int i = MAX_LOCALE; i < MAX_LOCALE*2-1; ++i)
5301        {
5302            std::string str = fields[i].GetCppString();
5303            if(!str.empty())
5304            {
5305                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
5306                if(idx >= 0)
5307                {
5308                    if(data.CastBarCaption.size() <= idx)
5309                        data.CastBarCaption.resize(idx+1);
5310
5311                    data.CastBarCaption[idx] = str;
5312                }
5313            }
5314        }
5315
5316    } while (result->NextRow());
5317
5318    delete result;
5319
5320    sLog.outString();
5321    sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() );
5322}
5323
5324void ObjectMgr::LoadGameobjectInfo()
5325{
5326    sGOStorage.Load();
5327
5328    // some checks
5329    for(uint32 id = 1; id < sGOStorage.MaxEntry; id++)
5330    {
5331        GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(id);
5332        if(!goInfo)
5333            continue;
5334
5335        switch(goInfo->type)
5336        {
5337            case GAMEOBJECT_TYPE_DOOR:                      //0
5338            {
5339                if(goInfo->door.lockId)
5340                {
5341                    if(!sLockStore.LookupEntry(goInfo->door.lockId))
5342                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
5343                            id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId);
5344                }
5345                break;
5346            }
5347            case GAMEOBJECT_TYPE_BUTTON:                    //1
5348            {
5349                if(goInfo->button.lockId)
5350                {
5351                    if(!sLockStore.LookupEntry(goInfo->button.lockId))
5352                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
5353                            id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId);
5354                }
5355                break;
5356            }
5357            case GAMEOBJECT_TYPE_CHEST:                     //3
5358            {
5359                if(goInfo->chest.lockId)
5360                {
5361                    if(!sLockStore.LookupEntry(goInfo->chest.lockId))
5362                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.",
5363                            id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId);
5364                }
5365                if(goInfo->chest.linkedTrapId)              // linked trap
5366                {
5367                    if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->chest.linkedTrapId))
5368                    {
5369                        if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
5370                            sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
5371                                id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
5372                    }
5373                    /* disable check for while
5374                    else
5375                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
5376                            id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId);
5377                    */
5378                }
5379                break;
5380            }
5381            case GAMEOBJECT_TYPE_TRAP:                      //6
5382            {
5383                /* disable check for while
5384                if(goInfo->trap.spellId)                    // spell
5385                {
5386                    if(!sSpellStore.LookupEntry(goInfo->trap.spellId))
5387                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
5388                            id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId);
5389                }
5390                */
5391                break;
5392            }
5393            case GAMEOBJECT_TYPE_CHAIR:                     //7
5394                if(goInfo->chair.height > 2)
5395                {
5396                    sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..2.",
5397                        id,goInfo->type,goInfo->chair.height);
5398
5399                    // prevent client and server unexpected work
5400                    const_cast<GameObjectInfo*>(goInfo)->chair.height = 0;
5401                }
5402                break;
5403            case GAMEOBJECT_TYPE_SPELL_FOCUS:               //8
5404            {
5405                if(goInfo->spellFocus.focusId)
5406                {
5407                    if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId))
5408                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.",
5409                            id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId);
5410                }
5411
5412                if(goInfo->spellFocus.linkedTrapId)         // linked trap
5413                {
5414                    if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->spellFocus.linkedTrapId))
5415                    {
5416                        if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
5417                            sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
5418                                id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
5419                    }
5420                    /* disable check for while
5421                    else
5422                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
5423                            id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId);
5424                    */
5425                }
5426                break;
5427            }
5428            case GAMEOBJECT_TYPE_GOOBER:                    //10
5429            {
5430                if(goInfo->goober.pageId)                   // pageId
5431                {
5432                    if(!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
5433                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.",
5434                            id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId);
5435                }
5436                /* disable check for while
5437                if(goInfo->goober.spellId)                  // spell
5438                {
5439                    if(!sSpellStore.LookupEntry(goInfo->goober.spellId))
5440                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.",
5441                            id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId);
5442                }
5443                */
5444                if(goInfo->goober.linkedTrapId)             // linked trap
5445                {
5446                    if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->goober.linkedTrapId))
5447                    {
5448                        if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
5449                            sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
5450                                id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
5451                    }
5452                    /* disable check for while
5453                    else
5454                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
5455                            id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId);
5456                    */
5457                }
5458                break;
5459            }
5460            case GAMEOBJECT_TYPE_MO_TRANSPORT:              //15
5461            {
5462                if(goInfo->moTransport.taxiPathId)
5463                {
5464                    if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty())
5465                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
5466                            id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId);
5467                }
5468                break;
5469            }
5470            case GAMEOBJECT_TYPE_SUMMONING_RITUAL:          //18
5471            {
5472                /* disabled
5473                if(goInfo->summoningRitual.spellId)
5474                {
5475                    if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId))
5476                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.",
5477                            id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId);
5478                }
5479                */
5480                break;
5481            }
5482            case GAMEOBJECT_TYPE_SPELLCASTER:               //22
5483            {
5484                if(goInfo->spellcaster.spellId)             // spell
5485                {
5486                    if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId))
5487                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
5488                            id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId);
5489                }
5490                break;
5491            }
5492        }
5493    }
5494
5495    sLog.outString( ">> Loaded %u game object templates", sGOStorage.RecordCount );
5496    sLog.outString();
5497}
5498
5499void ObjectMgr::LoadExplorationBaseXP()
5500{
5501    uint32 count = 0;
5502    QueryResult *result = WorldDatabase.Query("SELECT level,basexp FROM exploration_basexp");
5503
5504    if( !result )
5505    {
5506        barGoLink bar( 1 );
5507
5508        bar.step();
5509
5510        sLog.outString();
5511        sLog.outString( ">> Loaded %u BaseXP definitions", count );
5512        return;
5513    }
5514
5515    barGoLink bar( result->GetRowCount() );
5516
5517    do
5518    {
5519        bar.step();
5520
5521        Field *fields = result->Fetch();
5522        uint32 level  = fields[0].GetUInt32();
5523        uint32 basexp = fields[1].GetUInt32();
5524        mBaseXPTable[level] = basexp;
5525        ++count;
5526    }
5527    while (result->NextRow());
5528
5529    delete result;
5530
5531    sLog.outString();
5532    sLog.outString( ">> Loaded %u BaseXP definitions", count );
5533}
5534
5535uint32 ObjectMgr::GetBaseXP(uint32 level)
5536{
5537    return mBaseXPTable[level] ? mBaseXPTable[level] : 0;
5538}
5539
5540void ObjectMgr::LoadPetNames()
5541{
5542    uint32 count = 0;
5543    QueryResult *result = WorldDatabase.Query("SELECT word,entry,half FROM pet_name_generation");
5544
5545    if( !result )
5546    {
5547        barGoLink bar( 1 );
5548
5549        bar.step();
5550
5551        sLog.outString();
5552        sLog.outString( ">> Loaded %u pet name parts", count );
5553        return;
5554    }
5555
5556    barGoLink bar( result->GetRowCount() );
5557
5558    do
5559    {
5560        bar.step();
5561
5562        Field *fields = result->Fetch();
5563        std::string word = fields[0].GetString();
5564        uint32 entry     = fields[1].GetUInt32();
5565        bool   half      = fields[2].GetBool();
5566        if(half)
5567            PetHalfName1[entry].push_back(word);
5568        else
5569            PetHalfName0[entry].push_back(word);
5570        ++count;
5571    }
5572    while (result->NextRow());
5573    delete result;
5574
5575    sLog.outString();
5576    sLog.outString( ">> Loaded %u pet name parts", count );
5577}
5578
5579void ObjectMgr::LoadPetNumber()
5580{
5581    QueryResult* result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet");
5582    if(result)
5583    {
5584        Field *fields = result->Fetch();
5585        m_hiPetNumber = fields[0].GetUInt32()+1;
5586        delete result;
5587    }
5588
5589    barGoLink bar( 1 );
5590    bar.step();
5591
5592    sLog.outString();
5593    sLog.outString( ">> Loaded the max pet number: %d", m_hiPetNumber-1);
5594}
5595
5596std::string ObjectMgr::GeneratePetName(uint32 entry)
5597{
5598    std::vector<std::string> & list0 = PetHalfName0[entry];
5599    std::vector<std::string> & list1 = PetHalfName1[entry];
5600
5601    if(list0.empty() || list1.empty())
5602    {
5603        CreatureInfo const *cinfo = GetCreatureTemplate(entry);
5604        char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale());
5605        if(!petname)
5606            petname = cinfo->Name;
5607        return std::string(petname);
5608    }
5609
5610    return *(list0.begin()+urand(0, list0.size()-1)) + *(list1.begin()+urand(0, list1.size()-1));
5611}
5612
5613uint32 ObjectMgr::GeneratePetNumber()
5614{
5615    return ++m_hiPetNumber;
5616}
5617
5618void ObjectMgr::LoadCorpses()
5619{
5620    uint32 count = 0;
5621    //                                                     0           1           2           3            4    5     6     7            8         10
5622    QueryResult *result = CharacterDatabase.PQuery("SELECT position_x, position_y, position_z, orientation, map, data, time, corpse_type, instance, guid FROM corpse WHERE corpse_type <> 0");
5623
5624    if( !result )
5625    {
5626        barGoLink bar( 1 );
5627
5628        bar.step();
5629
5630        sLog.outString();
5631        sLog.outString( ">> Loaded %u corpses", count );
5632        return;
5633    }
5634
5635    barGoLink bar( result->GetRowCount() );
5636
5637    do
5638    {
5639        bar.step();
5640
5641        Field *fields = result->Fetch();
5642
5643        uint32 guid = fields[result->GetFieldCount()-1].GetUInt32();
5644
5645        Corpse *corpse = new Corpse;
5646        if(!corpse->LoadFromDB(guid,fields))
5647        {
5648            delete corpse;
5649            continue;
5650        }
5651
5652        ObjectAccessor::Instance().AddCorpse(corpse);
5653
5654        ++count;
5655    }
5656    while (result->NextRow());
5657    delete result;
5658
5659    sLog.outString();
5660    sLog.outString( ">> Loaded %u corpses", count );
5661}
5662
5663void ObjectMgr::LoadReputationOnKill()
5664{
5665    uint32 count = 0;
5666
5667    //                                                0            1                     2
5668    QueryResult *result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2,"
5669    //   3             4             5                   6             7             8                   9
5670        "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent "
5671        "FROM creature_onkill_reputation");
5672
5673    if(!result)
5674    {
5675        barGoLink bar(1);
5676
5677        bar.step();
5678
5679        sLog.outString();
5680        sLog.outErrorDb(">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty.");
5681        return;
5682    }
5683
5684    barGoLink bar(result->GetRowCount());
5685
5686    do
5687    {
5688        Field *fields = result->Fetch();
5689        bar.step();
5690
5691        uint32 creature_id = fields[0].GetUInt32();
5692
5693        ReputationOnKillEntry repOnKill;
5694        repOnKill.repfaction1          = fields[1].GetUInt32();
5695        repOnKill.repfaction2          = fields[2].GetUInt32();
5696        repOnKill.is_teamaward1        = fields[3].GetBool();
5697        repOnKill.reputation_max_cap1  = fields[4].GetUInt32();
5698        repOnKill.repvalue1            = fields[5].GetInt32();
5699        repOnKill.is_teamaward2        = fields[6].GetBool();
5700        repOnKill.reputation_max_cap2  = fields[7].GetUInt32();
5701        repOnKill.repvalue2            = fields[8].GetInt32();
5702        repOnKill.team_dependent       = fields[9].GetUInt8();
5703
5704        if(!GetCreatureTemplate(creature_id))
5705        {
5706            sLog.outErrorDb("Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped",creature_id);
5707            continue;
5708        }
5709
5710        if(repOnKill.repfaction1)
5711        {
5712            FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repOnKill.repfaction1);
5713            if(!factionEntry1)
5714            {
5715                sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction1);
5716                continue;
5717            }
5718        }
5719
5720        if(repOnKill.repfaction2)
5721        {
5722            FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repOnKill.repfaction2);
5723            if(!factionEntry2)
5724            {
5725                sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction2);
5726                continue;
5727            }
5728        }
5729
5730        mRepOnKill[creature_id] = repOnKill;
5731
5732        ++count;
5733    } while (result->NextRow());
5734
5735    delete result;
5736
5737    sLog.outString();
5738    sLog.outString(">> Loaded %u creature award reputation definitions", count);
5739}
5740
5741void ObjectMgr::LoadWeatherZoneChances()
5742{
5743    uint32 count = 0;
5744
5745    //                                                0     1                   2                   3                    4                   5                   6                    7                 8                 9                  10                  11                  12
5746    QueryResult *result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather");
5747
5748    if(!result)
5749    {
5750        barGoLink bar(1);
5751
5752        bar.step();
5753
5754        sLog.outString();
5755        sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty.");
5756        return;
5757    }
5758
5759    barGoLink bar(result->GetRowCount());
5760
5761    do
5762    {
5763        Field *fields = result->Fetch();
5764        bar.step();
5765
5766        uint32 zone_id = fields[0].GetUInt32();
5767
5768        WeatherZoneChances& wzc = mWeatherZoneMap[zone_id];
5769
5770        for(int season = 0; season < WEATHER_SEASONS; ++season)
5771        {
5772            wzc.data[season].rainChance  = fields[season * (MAX_WEATHER_TYPE-1) + 1].GetUInt32();
5773            wzc.data[season].snowChance  = fields[season * (MAX_WEATHER_TYPE-1) + 2].GetUInt32();
5774            wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE-1) + 3].GetUInt32();
5775
5776            if(wzc.data[season].rainChance > 100)
5777            {
5778                wzc.data[season].rainChance = 25;
5779                sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%",zone_id,season);
5780            }
5781
5782            if(wzc.data[season].snowChance > 100)
5783            {
5784                wzc.data[season].snowChance = 25;
5785                sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%",zone_id,season);
5786            }
5787
5788            if(wzc.data[season].stormChance > 100)
5789            {
5790                wzc.data[season].stormChance = 25;
5791                sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%",zone_id,season);
5792            }
5793        }
5794
5795        ++count;
5796    } while (result->NextRow());
5797
5798    delete result;
5799
5800    sLog.outString();
5801    sLog.outString(">> Loaded %u weather definitions", count);
5802}
5803
5804void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t)
5805{
5806    mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t;
5807    WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance);
5808    if(t)
5809        WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance);
5810}
5811
5812void ObjectMgr::DeleteCreatureData(uint32 guid)
5813{
5814    // remove mapid*cellid -> guid_set map
5815    CreatureData const* data = GetCreatureData(guid);
5816    if(data)
5817        RemoveCreatureFromGrid(guid, data);
5818
5819    mCreatureDataMap.erase(guid);
5820}
5821
5822void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t)
5823{
5824    mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t;
5825    WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance);
5826    if(t)
5827        WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance);
5828}
5829
5830void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance)
5831{
5832    RespawnTimes::iterator next;
5833
5834    for(RespawnTimes::iterator itr = mGORespawnTimes.begin(); itr != mGORespawnTimes.end(); itr = next)
5835    {
5836        next = itr;
5837        ++next;
5838
5839        if(GUID_HIPART(itr->first)==instance)
5840            mGORespawnTimes.erase(itr);
5841    }
5842
5843    for(RespawnTimes::iterator itr = mCreatureRespawnTimes.begin(); itr != mCreatureRespawnTimes.end(); itr = next)
5844    {
5845        next = itr;
5846        ++next;
5847
5848        if(GUID_HIPART(itr->first)==instance)
5849            mCreatureRespawnTimes.erase(itr);
5850    }
5851
5852    WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", instance);
5853    WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", instance);
5854}
5855
5856void ObjectMgr::DeleteGOData(uint32 guid)
5857{
5858    // remove mapid*cellid -> guid_set map
5859    GameObjectData const* data = GetGOData(guid);
5860    if(data)
5861        RemoveGameobjectFromGrid(guid, data);
5862
5863    mGameObjectDataMap.erase(guid);
5864}
5865
5866void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance)
5867{
5868    // corpses are always added to spawn mode 0 and they are spawned by their instance id
5869    CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid];
5870    cell_guids.corpses[player_guid] = instance;
5871}
5872
5873void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid)
5874{
5875    // corpses are always added to spawn mode 0 and they are spawned by their instance id
5876    CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid];
5877    cell_guids.corpses.erase(player_guid);
5878}
5879
5880void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map,char const* table)
5881{
5882    map.clear();                                            // need for reload case
5883
5884    uint32 count = 0;
5885
5886    QueryResult *result = WorldDatabase.PQuery("SELECT id,quest FROM %s",table);
5887
5888    if(!result)
5889    {
5890        barGoLink bar(1);
5891
5892        bar.step();
5893
5894        sLog.outString();
5895        sLog.outErrorDb(">> Loaded 0 quest relations from %s. DB table `%s` is empty.",table,table);
5896        return;
5897    }
5898
5899    barGoLink bar(result->GetRowCount());
5900
5901    do
5902    {
5903        Field *fields = result->Fetch();
5904        bar.step();
5905
5906        uint32 id    = fields[0].GetUInt32();
5907        uint32 quest = fields[1].GetUInt32();
5908
5909        if(mQuestTemplates.find(quest) == mQuestTemplates.end())
5910        {
5911            sLog.outErrorDb("Table `%s: Quest %u listed for entry %u does not exist.",table,quest,id);
5912            continue;
5913        }
5914
5915        map.insert(QuestRelations::value_type(id,quest));
5916
5917        ++count;
5918    } while (result->NextRow());
5919
5920    delete result;
5921
5922    sLog.outString();
5923    sLog.outString(">> Loaded %u quest relations from %s", count,table);
5924}
5925
5926void ObjectMgr::LoadGameobjectQuestRelations()
5927{
5928    LoadQuestRelationsHelper(mGOQuestRelations,"gameobject_questrelation");
5929
5930    for(QuestRelations::iterator itr = mGOQuestRelations.begin(); itr != mGOQuestRelations.end(); ++itr)
5931    {
5932        GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first);
5933        if(!goInfo)
5934            sLog.outErrorDb("Table `gameobject_questrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second);
5935        else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
5936            sLog.outErrorDb("Table `gameobject_questrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second);
5937    }
5938}
5939
5940void ObjectMgr::LoadGameobjectInvolvedRelations()
5941{
5942    LoadQuestRelationsHelper(mGOQuestInvolvedRelations,"gameobject_involvedrelation");
5943
5944    for(QuestRelations::iterator itr = mGOQuestInvolvedRelations.begin(); itr != mGOQuestInvolvedRelations.end(); ++itr)
5945    {
5946        GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first);
5947        if(!goInfo)
5948            sLog.outErrorDb("Table `gameobject_involvedrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second);
5949        else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
5950            sLog.outErrorDb("Table `gameobject_involvedrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second);
5951    }
5952}
5953
5954void ObjectMgr::LoadCreatureQuestRelations()
5955{
5956    LoadQuestRelationsHelper(mCreatureQuestRelations,"creature_questrelation");
5957
5958    for(QuestRelations::iterator itr = mCreatureQuestRelations.begin(); itr != mCreatureQuestRelations.end(); ++itr)
5959    {
5960        CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
5961        if(!cInfo)
5962            sLog.outErrorDb("Table `creature_questrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second);
5963        else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
5964            sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second);
5965    }
5966}
5967
5968void ObjectMgr::LoadCreatureInvolvedRelations()
5969{
5970    LoadQuestRelationsHelper(mCreatureQuestInvolvedRelations,"creature_involvedrelation");
5971
5972    for(QuestRelations::iterator itr = mCreatureQuestInvolvedRelations.begin(); itr != mCreatureQuestInvolvedRelations.end(); ++itr)
5973    {
5974        CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
5975        if(!cInfo)
5976            sLog.outErrorDb("Table `creature_involvedrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second);
5977        else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
5978            sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second);
5979    }
5980}
5981
5982void ObjectMgr::LoadReservedPlayersNames()
5983{
5984    m_ReservedNames.clear();                                // need for reload case
5985
5986    QueryResult *result = WorldDatabase.PQuery("SELECT name FROM reserved_name");
5987
5988    uint32 count = 0;
5989
5990    if( !result )
5991    {
5992        barGoLink bar( 1 );
5993        bar.step();
5994
5995        sLog.outString();
5996        sLog.outString( ">> Loaded %u reserved player names", count );
5997        return;
5998    }
5999
6000    barGoLink bar( result->GetRowCount() );
6001
6002    Field* fields;
6003    do
6004    {
6005        bar.step();
6006        fields = result->Fetch();
6007        std::string name= fields[0].GetCppString();
6008        if(normalizePlayerName(name))
6009        {
6010            m_ReservedNames.insert(name);
6011            ++count;
6012        }
6013    } while ( result->NextRow() );
6014
6015    delete result;
6016
6017    sLog.outString();
6018    sLog.outString( ">> Loaded %u reserved player names", count );
6019}
6020
6021enum LanguageType
6022{
6023    LT_BASIC_LATIN    = 0x0000,
6024    LT_EXTENDEN_LATIN = 0x0001,
6025    LT_CYRILLIC       = 0x0002,
6026    LT_EAST_ASIA      = 0x0004,
6027    LT_ANY            = 0xFFFF
6028};
6029
6030static LanguageType GetRealmLanguageType(bool create)
6031{
6032    switch(sWorld.getConfig(CONFIG_REALM_ZONE))
6033    {
6034        case REALM_ZONE_UNKNOWN:                            // any language
6035        case REALM_ZONE_DEVELOPMENT:
6036        case REALM_ZONE_TEST_SERVER:
6037        case REALM_ZONE_QA_SERVER:
6038            return LT_ANY;
6039        case REALM_ZONE_UNITED_STATES:                      // extended-Latin
6040        case REALM_ZONE_OCEANIC:
6041        case REALM_ZONE_LATIN_AMERICA:
6042        case REALM_ZONE_ENGLISH:
6043        case REALM_ZONE_GERMAN:
6044        case REALM_ZONE_FRENCH:
6045        case REALM_ZONE_SPANISH:
6046            return LT_EXTENDEN_LATIN;
6047        case REALM_ZONE_KOREA:                              // East-Asian
6048        case REALM_ZONE_TAIWAN:
6049        case REALM_ZONE_CHINA:
6050            return LT_EAST_ASIA;
6051        case REALM_ZONE_RUSSIAN:                            // Cyrillic
6052            return LT_CYRILLIC;
6053        default:
6054            return create ? LT_BASIC_LATIN : LT_ANY;        // basic-Latin at create, any at login
6055    }
6056}
6057
6058bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bool create = false)
6059{
6060    if(strictMask==0)                                       // any language, ignore realm
6061    {
6062        if(isExtendedLatinString(wstr,numericOrSpace))
6063            return true;
6064        if(isCyrillicString(wstr,numericOrSpace))
6065            return true;
6066        if(isEastAsianString(wstr,numericOrSpace))
6067            return true;
6068        return false;
6069    }
6070
6071    if(strictMask & 0x2)                                    // realm zone specific
6072    {
6073        LanguageType lt = GetRealmLanguageType(create);
6074        if(lt & LT_EXTENDEN_LATIN)
6075            if(isExtendedLatinString(wstr,numericOrSpace))
6076                return true;
6077        if(lt & LT_CYRILLIC)
6078            if(isCyrillicString(wstr,numericOrSpace))
6079                return true;
6080        if(lt & LT_EAST_ASIA)
6081            if(isEastAsianString(wstr,numericOrSpace))
6082                return true;
6083    }
6084
6085    if(strictMask & 0x1)                                    // basic latin
6086    {
6087        if(isBasicLatinString(wstr,numericOrSpace))
6088            return true;
6089    }
6090
6091    return false;
6092}
6093
6094bool ObjectMgr::IsValidName( std::string name, bool create )
6095{
6096    std::wstring wname;
6097    if(!Utf8toWStr(name,wname))
6098        return false;
6099
6100    if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME)
6101        return false;
6102
6103    uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES);
6104
6105    return isValidString(wname,strictMask,false,create);
6106}
6107
6108bool ObjectMgr::IsValidCharterName( std::string name )
6109{
6110    std::wstring wname;
6111    if(!Utf8toWStr(name,wname))
6112        return false;
6113
6114    if(wname.size() < 1)
6115        return false;
6116
6117    uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES);
6118
6119    return isValidString(wname,strictMask,true);
6120}
6121
6122bool ObjectMgr::IsValidPetName( std::string name )
6123{
6124    std::wstring wname;
6125    if(!Utf8toWStr(name,wname))
6126        return false;
6127
6128    if(wname.size() < 1)
6129        return false;
6130
6131    uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES);
6132
6133    return isValidString(wname,strictMask,false);
6134}
6135
6136int ObjectMgr::GetIndexForLocale( LocaleConstant loc )
6137{
6138    if(loc==LOCALE_enUS)
6139        return -1;
6140
6141    for(size_t i=0;i < m_LocalForIndex.size(); ++i)
6142        if(m_LocalForIndex[i]==loc)
6143            return i;
6144
6145    return -1;
6146}
6147
6148LocaleConstant ObjectMgr::GetLocaleForIndex(int i)
6149{
6150    if (i<0 || i>=m_LocalForIndex.size())
6151        return LOCALE_enUS;
6152
6153    return m_LocalForIndex[i];
6154}
6155
6156int ObjectMgr::GetOrNewIndexForLocale( LocaleConstant loc )
6157{
6158    if(loc==LOCALE_enUS)
6159        return -1;
6160
6161    for(size_t i=0;i < m_LocalForIndex.size(); ++i)
6162        if(m_LocalForIndex[i]==loc)
6163            return i;
6164
6165    m_LocalForIndex.push_back(loc);
6166    return m_LocalForIndex.size()-1;
6167}
6168
6169void ObjectMgr::LoadBattleMastersEntry()
6170{
6171    mBattleMastersMap.clear();                              // need for reload case
6172
6173    QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
6174
6175    uint32 count = 0;
6176
6177    if( !result )
6178    {
6179        barGoLink bar( 1 );
6180        bar.step();
6181
6182        sLog.outString();
6183        sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
6184        return;
6185    }
6186
6187    barGoLink bar( result->GetRowCount() );
6188
6189    do
6190    {
6191        ++count;
6192        bar.step();
6193
6194        Field *fields = result->Fetch();
6195
6196        uint32 entry = fields[0].GetUInt32();
6197        uint32 bgTypeId  = fields[1].GetUInt32();
6198
6199        mBattleMastersMap[entry] = bgTypeId;
6200
6201    } while( result->NextRow() );
6202
6203    delete result;
6204
6205    sLog.outString();
6206    sLog.outString( ">> Loaded %u battlemaster entries", count );
6207}
6208
6209void ObjectMgr::LoadGameObjectForQuests()
6210{
6211    mGameObjectForQuestSet.clear();                         // need for reload case
6212
6213    uint32 count = 0;
6214
6215    // collect GO entries for GO that must activated
6216    for(uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry)
6217    {
6218        GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(go_entry);
6219        if(!goInfo)
6220            continue;
6221
6222        switch(goInfo->type)
6223        {
6224            // scan GO chest with loot including quest items
6225            case GAMEOBJECT_TYPE_CHEST:
6226            {
6227                uint32 loot_id = GameObject::GetLootId(goInfo);
6228
6229                // find quest loot for GO
6230                if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id))
6231                {
6232                    mGameObjectForQuestSet.insert(go_entry);
6233                    ++count;
6234                }
6235                break;
6236            }
6237            case GAMEOBJECT_TYPE_GOOBER:
6238            {
6239                if(goInfo->goober.questId)                  //quests objects
6240                {
6241                    mGameObjectForQuestSet.insert(go_entry);
6242                    count++;
6243                }
6244                break;
6245            }
6246            default:
6247                break;
6248        }
6249    }
6250
6251    sLog.outString();
6252    sLog.outString( ">> Loaded %u GameObject for quests", count );
6253}
6254
6255bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value)
6256{
6257    // cleanup affected map part for reloading case
6258    for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();)
6259    {
6260        if(itr->first >= min_value && itr->first <= max_value)
6261        {
6262            TrinityStringLocaleMap::iterator itr2 = itr;
6263            ++itr;
6264            mTrinityStringLocaleMap.erase(itr2);
6265        }
6266        else
6267            ++itr;
6268    }
6269
6270    QueryResult *result = db.PQuery("SELECT entry,content_default,content_loc1,content_loc2,content_loc3,content_loc4,content_loc5,content_loc6,content_loc7,content_loc8 FROM %s",table);
6271
6272    if(!result)
6273    {
6274        barGoLink bar(1);
6275
6276        bar.step();
6277
6278        sLog.outString("");
6279        if(min_value > 0)                                   // error only in case internal strings
6280            sLog.outErrorDb(">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.",table);
6281        else
6282            sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table);
6283        return false;
6284    }
6285
6286    uint32 count = 0;
6287
6288    barGoLink bar(result->GetRowCount());
6289
6290    do
6291    {
6292        Field *fields = result->Fetch();
6293        bar.step();
6294
6295        int32 entry = fields[0].GetInt32();
6296
6297        if(entry==0)
6298        {
6299            sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.",table);
6300            continue;
6301        }
6302        else if(entry < min_value || entry > max_value)
6303        {
6304            int32 start = min_value > 0 ? min_value : max_value;
6305            int32 end   = min_value > 0 ? max_value : min_value;
6306            sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,start,end);
6307            continue;
6308        }
6309
6310        TrinityStringLocale& data = mTrinityStringLocaleMap[entry];
6311
6312        if(data.Content.size() > 0)
6313        {
6314            sLog.outErrorDb("Table `%s` contain data for already loaded entry  %i (from another table?), ignored.",table,entry);
6315            continue;
6316        }
6317
6318        data.Content.resize(1);
6319        ++count;
6320
6321        // 0 -> default, idx in to idx+1
6322        data.Content[0] = fields[1].GetCppString();
6323
6324        for(int i = 1; i < MAX_LOCALE; ++i)
6325        {
6326            std::string str = fields[i+1].GetCppString();
6327            if(!str.empty())
6328            {
6329                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
6330                if(idx >= 0)
6331                {
6332                    // 0 -> default, idx in to idx+1
6333                    if(data.Content.size() <= idx+1)
6334                        data.Content.resize(idx+2);
6335
6336                    data.Content[idx+1] = str;
6337                }
6338            }
6339        }
6340    } while (result->NextRow());
6341
6342    delete result;
6343
6344    sLog.outString();
6345    if(min_value > 0)                                       // internal Trinity strings
6346        sLog.outString( ">> Loaded %u Trinity strings from table %s", count,table);
6347    else
6348        sLog.outString( ">> Loaded %u string templates from %s", count,table);
6349
6350    return true;
6351}
6352
6353const char *ObjectMgr::GetTrinityString(int32 entry, int locale_idx) const
6354{
6355    // locale_idx==-1 -> default, locale_idx >= 0 in to idx+1
6356    // Content[0] always exist if exist TrinityStringLocale
6357    if(TrinityStringLocale const *msl = GetTrinityStringLocale(entry))
6358    {
6359        if(msl->Content.size() > locale_idx+1 && !msl->Content[locale_idx+1].empty())
6360            return msl->Content[locale_idx+1].c_str();
6361        else
6362            return msl->Content[0].c_str();
6363    }
6364
6365    if(entry > 0)
6366        sLog.outErrorDb("Entry %i not found in `trinity_string` table.",entry);
6367    else
6368        sLog.outErrorDb("Trinity string entry %i not found in DB.",entry);
6369    return "<error>";
6370}
6371
6372void ObjectMgr::LoadSpellDisabledEntrys()
6373{
6374    m_DisabledPlayerSpells.clear();                                // need for reload case
6375    m_DisabledCreatureSpells.clear();
6376    QueryResult *result = WorldDatabase.Query("SELECT entry, disable_mask FROM spell_disabled");
6377
6378    uint32 total_count = 0;
6379
6380    if( !result )
6381    {
6382        barGoLink bar( 1 );
6383        bar.step();
6384
6385        sLog.outString();
6386        sLog.outString( ">> Loaded %u disabled spells", total_count );
6387        return;
6388    }
6389
6390    barGoLink bar( result->GetRowCount() );
6391
6392    Field* fields;
6393    do
6394    {
6395        bar.step();
6396        fields = result->Fetch();
6397        uint32 spellid = fields[0].GetUInt32();
6398        if(!sSpellStore.LookupEntry(spellid))
6399        {
6400            sLog.outErrorDb("Spell entry %u from `spell_disabled` doesn't exist in dbc, ignoring.",spellid);
6401            continue;
6402        }
6403        uint32 disable_mask = fields[1].GetUInt32();
6404        if(disable_mask & SPELL_DISABLE_PLAYER)
6405            m_DisabledPlayerSpells.insert(spellid);
6406        if(disable_mask & SPELL_DISABLE_CREATURE)
6407            m_DisabledCreatureSpells.insert(spellid);
6408        ++total_count;
6409   } while ( result->NextRow() );
6410
6411    delete result;
6412
6413    sLog.outString();
6414    sLog.outString( ">> Loaded %u disabled spells from `spell_disabled`", total_count);
6415}
6416
6417void ObjectMgr::LoadFishingBaseSkillLevel()
6418{
6419    mFishingBaseForArea.clear();                            // for relaod case
6420
6421    uint32 count = 0;
6422    QueryResult *result = WorldDatabase.Query("SELECT entry,skill FROM skill_fishing_base_level");
6423
6424    if( !result )
6425    {
6426        barGoLink bar( 1 );
6427
6428        bar.step();
6429
6430        sLog.outString();
6431        sLog.outErrorDb(">> Loaded `skill_fishing_base_level`, table is empty!");
6432        return;
6433    }
6434
6435    barGoLink bar( result->GetRowCount() );
6436
6437    do
6438    {
6439        bar.step();
6440
6441        Field *fields = result->Fetch();
6442        uint32 entry  = fields[0].GetUInt32();
6443        int32 skill   = fields[1].GetInt32();
6444
6445        AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry);
6446        if(!fArea)
6447        {
6448            sLog.outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist",entry);
6449            continue;
6450        }
6451
6452        mFishingBaseForArea[entry] = skill;
6453        ++count;
6454    }
6455    while (result->NextRow());
6456
6457    delete result;
6458
6459    sLog.outString();
6460    sLog.outString( ">> Loaded %u areas for fishing base skill level", count );
6461}
6462
6463// Searches for the same condition already in Conditions store
6464// Returns Id if found, else adds it to Conditions and returns Id
6465uint16 ObjectMgr::GetConditionId( ConditionType condition, uint32 value1, uint32 value2 )
6466{
6467    PlayerCondition lc = PlayerCondition(condition, value1, value2);
6468    for (uint16 i=0; i < mConditions.size(); ++i)
6469    {
6470        if (lc == mConditions[i])
6471            return i;
6472    }
6473
6474    mConditions.push_back(lc);
6475
6476    if(mConditions.size() > 0xFFFF)
6477    {
6478        sLog.outError("Conditions store overflow! Current and later loaded conditions will ignored!");
6479        return 0;
6480    }
6481
6482    return mConditions.size() - 1;
6483}
6484
6485bool ObjectMgr::CheckDeclinedNames( std::wstring mainpart, DeclinedName const& names )
6486{
6487    for(int i =0; i < MAX_DECLINED_NAME_CASES; ++i)
6488    {
6489        std::wstring wname;
6490        if(!Utf8toWStr(names.name[i],wname))
6491            return false;
6492
6493        if(mainpart!=GetMainPartOfName(wname,i+1))
6494            return false;
6495    }
6496    return true;
6497}
6498
6499const char* ObjectMgr::GetAreaTriggerScriptName(uint32 id)
6500{
6501    AreaTriggerScriptMap::const_iterator i = mAreaTriggerScripts.find(id);
6502    if(i!= mAreaTriggerScripts.end())
6503        return i->second.c_str();
6504    return "";
6505}
6506
6507// Checks if player meets the condition
6508bool PlayerCondition::Meets(Player const * player) const
6509{
6510    if( !player )
6511        return false;                                       // player not present, return false
6512
6513    switch (condition)
6514    {
6515        case CONDITION_NONE:
6516            return true;                                    // empty condition, always met
6517        case CONDITION_AURA:
6518            return player->HasAura(value1, value2);
6519        case CONDITION_ITEM:
6520            return player->HasItemCount(value1, value2);
6521        case CONDITION_ITEM_EQUIPPED:
6522            return player->GetItemOrItemWithGemEquipped(value1) != NULL;
6523        case CONDITION_ZONEID:
6524            return player->GetZoneId() == value1;
6525        case CONDITION_REPUTATION_RANK:
6526        {
6527            FactionEntry const* faction = sFactionStore.LookupEntry(value1);
6528            return faction && player->GetReputationRank(faction) >= value2;
6529        }
6530        case CONDITION_TEAM:
6531            return player->GetTeam() == value1;
6532        case CONDITION_SKILL:
6533            return player->HasSkill(value1) && player->GetBaseSkillValue(value1) >= value2;
6534        case CONDITION_QUESTREWARDED:
6535            return player->GetQuestRewardStatus(value1);
6536        case CONDITION_QUESTTAKEN:
6537        {
6538            QuestStatus status = player->GetQuestStatus(value1);
6539            return (status == QUEST_STATUS_INCOMPLETE);
6540        }
6541        case CONDITION_AD_COMMISSION_AURA:
6542        {
6543            Unit::AuraMap const& auras = player->GetAuras();
6544            for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6545                if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual==3580)
6546                    return true;
6547            return false;
6548        }
6549        default:
6550            return false;
6551    }
6552}
6553
6554// Verification of condition values validity
6555bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 value2)
6556{
6557    if( condition >= MAX_CONDITION)                         // Wrong condition type
6558    {
6559        sLog.outErrorDb("Condition has bad type of %u, skipped ", condition );
6560        return false;
6561    }
6562
6563    switch (condition)
6564    {
6565        case CONDITION_AURA:
6566        {
6567            if(!sSpellStore.LookupEntry(value1))
6568            {
6569                sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1);
6570                return false;
6571            }
6572            if(value2 > 2)
6573            {
6574                sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2);
6575                return false;
6576            }
6577            break;
6578        }
6579        case CONDITION_ITEM:
6580        {
6581            ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
6582            if(!proto)
6583            {
6584                sLog.outErrorDb("Item condition requires to have non existing item (%u), skipped", value1);
6585                return false;
6586            }
6587            break;
6588        }
6589        case CONDITION_ITEM_EQUIPPED:
6590        {
6591            ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
6592            if(!proto)
6593            {
6594                sLog.outErrorDb("ItemEquipped condition requires to have non existing item (%u) equipped, skipped", value1);
6595                return false;
6596            }
6597            break;
6598        }
6599        case CONDITION_ZONEID:
6600        {
6601            AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(value1);
6602            if(!areaEntry)
6603            {
6604                sLog.outErrorDb("Zone condition requires to be in non existing area (%u), skipped", value1);
6605                return false;
6606            }
6607            if(areaEntry->zone != 0)
6608            {
6609                sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", value1);
6610                return false;
6611            }
6612            break;
6613        }
6614        case CONDITION_REPUTATION_RANK:
6615        {
6616            FactionEntry const* factionEntry = sFactionStore.LookupEntry(value1);
6617            if(!factionEntry)
6618            {
6619                sLog.outErrorDb("Reputation condition requires to have reputation non existing faction (%u), skipped", value1);
6620                return false;
6621            }
6622            break;
6623        }
6624        case CONDITION_TEAM:
6625        {
6626            if (value1 != ALLIANCE && value1 != HORDE)
6627            {
6628                sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", value1);
6629                return false;
6630            }
6631            break;
6632        }
6633        case CONDITION_SKILL:
6634        {
6635            SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(value1);
6636            if (!pSkill)
6637            {
6638                sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", value1);
6639                return false;
6640            }
6641            if (value2 < 1 || value2 > sWorld.GetConfigMaxSkillValue() )
6642            {
6643                sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", value2);
6644                return false;
6645            }
6646            break;
6647        }
6648        case CONDITION_QUESTREWARDED:
6649        case CONDITION_QUESTTAKEN:
6650        {
6651            Quest const *Quest = objmgr.GetQuestTemplate(value1);
6652            if (!Quest)
6653            {
6654                sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", value1);
6655                return false;
6656            }
6657            if(value2)
6658                sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
6659            break;
6660        }
6661        case CONDITION_AD_COMMISSION_AURA:
6662        {
6663            if(value1)
6664                sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", value1);
6665            if(value2)
6666                sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
6667            break;
6668        }
6669    }
6670    return true;
6671}
6672
6673SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
6674{
6675    switch(pSkill->categoryId)
6676    {
6677        case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE;
6678        case SKILL_CATEGORY_WEAPON:
6679            if(pSkill->id!=SKILL_FIST_WEAPONS)
6680                return SKILL_RANGE_LEVEL;
6681            else
6682                return SKILL_RANGE_MONO;
6683        case SKILL_CATEGORY_ARMOR:
6684        case SKILL_CATEGORY_CLASS:
6685            if(pSkill->id != SKILL_POISONS && pSkill->id != SKILL_LOCKPICKING)
6686                return SKILL_RANGE_MONO;
6687            else
6688                return SKILL_RANGE_LEVEL;
6689        case SKILL_CATEGORY_SECONDARY:
6690        case SKILL_CATEGORY_PROFESSION:
6691            // not set skills for professions and racial abilities
6692            if(IsProfessionSkill(pSkill->id))
6693                return SKILL_RANGE_RANK;
6694            else if(racial)
6695                return SKILL_RANGE_NONE;
6696            else
6697                return SKILL_RANGE_MONO;
6698        default:
6699        case SKILL_CATEGORY_ATTRIBUTES:                     //not found in dbc
6700        case SKILL_CATEGORY_NOT_DISPLAYED:                  //only GENEREC(DND)
6701            return SKILL_RANGE_NONE;
6702    }
6703}
6704
6705void ObjectMgr::LoadGameTele()
6706{
6707    m_GameTeleMap.clear();                                  // for relaod case
6708
6709    uint32 count = 0;
6710    QueryResult *result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele");
6711
6712    if( !result )
6713    {
6714        barGoLink bar( 1 );
6715
6716        bar.step();
6717
6718        sLog.outString();
6719        sLog.outErrorDb(">> Loaded `game_tele`, table is empty!");
6720        return;
6721    }
6722
6723    barGoLink bar( result->GetRowCount() );
6724
6725    do
6726    {
6727        bar.step();
6728
6729        Field *fields = result->Fetch();
6730
6731        uint32 id         = fields[0].GetUInt32();
6732
6733        GameTele gt;
6734
6735        gt.position_x     = fields[1].GetFloat();
6736        gt.position_y     = fields[2].GetFloat();
6737        gt.position_z     = fields[3].GetFloat();
6738        gt.orientation    = fields[4].GetFloat();
6739        gt.mapId          = fields[5].GetUInt32();
6740        gt.name           = fields[6].GetCppString();
6741
6742        if(!MapManager::IsValidMapCoord(gt.mapId,gt.position_x,gt.position_y,gt.position_z,gt.orientation))
6743        {
6744            sLog.outErrorDb("Wrong position for id %u (name: %s) in `game_tele` table, ignoring.",id,gt.name.c_str());
6745            continue;
6746        }
6747
6748        if(!Utf8toWStr(gt.name,gt.wnameLow))
6749        {
6750            sLog.outErrorDb("Wrong UTF8 name for id %u in `game_tele` table, ignoring.",id);
6751            continue;
6752        }
6753
6754        wstrToLower( gt.wnameLow );
6755
6756        m_GameTeleMap[id] = gt;
6757
6758        ++count;
6759    }
6760    while (result->NextRow());
6761
6762    delete result;
6763
6764    sLog.outString();
6765    sLog.outString( ">> Loaded %u game tele's", count );
6766}
6767
6768GameTele const* ObjectMgr::GetGameTele(std::string name) const
6769{
6770    // explicit name case
6771    std::wstring wname;
6772    if(!Utf8toWStr(name,wname))
6773        return false;
6774
6775    // converting string that we try to find to lower case
6776    wstrToLower( wname );
6777
6778    for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
6779        if(itr->second.wnameLow == wname)
6780            return &itr->second;
6781
6782    return NULL;
6783}
6784
6785bool ObjectMgr::AddGameTele(GameTele& tele)
6786{
6787    // find max id
6788    uint32 new_id = 0;
6789    for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
6790        if(itr->first > new_id)
6791            new_id = itr->first;
6792   
6793    // use next
6794    ++new_id;
6795
6796    if(!Utf8toWStr(tele.name,tele.wnameLow))
6797        return false;
6798
6799    wstrToLower( tele.wnameLow );
6800
6801    m_GameTeleMap[new_id] = tele;
6802
6803    return WorldDatabase.PExecuteLog("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')",
6804        new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str());
6805}
6806
6807bool ObjectMgr::DeleteGameTele(std::string name)
6808{
6809    // explicit name case
6810    std::wstring wname;
6811    if(!Utf8toWStr(name,wname))
6812        return false;
6813
6814    // converting string that we try to find to lower case
6815    wstrToLower( wname );
6816
6817    for(GameTeleMap::iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
6818    {
6819        if(itr->second.wnameLow == wname)
6820        {
6821            WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str());
6822            m_GameTeleMap.erase(itr);
6823            return true;
6824        }
6825    }
6826
6827    return false;
6828}
6829
6830void ObjectMgr::LoadTrainerSpell()
6831{
6832    // For reload case
6833    for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr)
6834        itr->second.Clear();
6835    m_mCacheTrainerSpellMap.clear();
6836
6837    std::set<uint32> skip_trainers;
6838
6839    QueryResult *result = WorldDatabase.PQuery("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer");
6840
6841    if( !result )
6842    {
6843        barGoLink bar( 1 );
6844
6845        bar.step();
6846
6847        sLog.outString();
6848        sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!");
6849        return;
6850    }
6851
6852    barGoLink bar( result->GetRowCount() );
6853
6854    uint32 count = 0;
6855    do
6856    {
6857        bar.step();
6858
6859        Field* fields = result->Fetch();
6860
6861        uint32 entry  = fields[0].GetUInt32();
6862        uint32 spell  = fields[1].GetUInt32();
6863
6864        CreatureInfo const* cInfo = GetCreatureTemplate(entry);
6865
6866        if(!cInfo)
6867        {
6868            sLog.outErrorDb("Table `npc_trainer` have entry for not existed creature template (Entry: %u), ignore", entry);
6869            continue;
6870        }
6871
6872        if(!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
6873        {
6874            if(skip_trainers.count(entry) == 0)
6875            {
6876                sLog.outErrorDb("Table `npc_trainer` have data for not creature template (Entry: %u) without trainer flag, ignore", entry);
6877                skip_trainers.insert(entry);
6878            }
6879            continue;
6880        }
6881
6882        SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell);
6883        if(!spellinfo)
6884        {
6885            sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u ) has non existing spell %u, ignore", entry,spell);
6886            continue;
6887        }
6888
6889        if(!SpellMgr::IsSpellValid(spellinfo))
6890        {
6891            sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell);
6892            continue;
6893        }
6894
6895        TrainerSpell* pTrainerSpell = new TrainerSpell();
6896        pTrainerSpell->spell         = spell;
6897        pTrainerSpell->spellcost     = fields[2].GetUInt32();
6898        pTrainerSpell->reqskill      = fields[3].GetUInt32();
6899        pTrainerSpell->reqskillvalue = fields[4].GetUInt32();
6900        pTrainerSpell->reqlevel      = fields[5].GetUInt32();
6901
6902        if(!pTrainerSpell->reqlevel)
6903            pTrainerSpell->reqlevel = spellinfo->spellLevel;
6904
6905
6906        TrainerSpellData& data = m_mCacheTrainerSpellMap[entry];
6907
6908        if(SpellMgr::IsProfessionSpell(spell))
6909            data.trainerType = 2;
6910
6911        data.spellList.push_back(pTrainerSpell);
6912        ++count;
6913
6914    } while (result->NextRow());
6915    delete result;
6916
6917    sLog.outString();
6918    sLog.outString( ">> Loaded Trainers %d", count );
6919}
6920
6921void ObjectMgr::LoadVendors()
6922{
6923    // For reload case
6924    for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr)
6925        itr->second.Clear();
6926    m_mCacheVendorItemMap.clear();
6927
6928    std::set<uint32> skip_vendors;
6929
6930    QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor");
6931    if( !result )
6932    {
6933        barGoLink bar( 1 );
6934
6935        bar.step();
6936
6937        sLog.outString();
6938        sLog.outErrorDb(">> Loaded `npc_vendor`, table is empty!");
6939        return;
6940    }
6941
6942    barGoLink bar( result->GetRowCount() );
6943
6944    uint32 count = 0;
6945    do
6946    {
6947        bar.step();
6948        Field* fields = result->Fetch();
6949
6950        uint32 entry        = fields[0].GetUInt32();
6951        uint32 item_id      = fields[1].GetUInt32();
6952        uint32 maxcount     = fields[2].GetUInt32();
6953        uint32 incrtime     = fields[3].GetUInt32();
6954        uint32 ExtendedCost = fields[4].GetUInt32();
6955
6956        if(!IsVendorItemValid(entry,item_id,maxcount,incrtime,ExtendedCost,NULL,&skip_vendors))
6957            continue;
6958
6959        VendorItemData& vList = m_mCacheVendorItemMap[entry];
6960
6961        vList.AddItem(item_id,maxcount,incrtime,ExtendedCost);
6962        ++count;
6963
6964    } while (result->NextRow());
6965    delete result;
6966
6967    sLog.outString();
6968    sLog.outString( ">> Loaded %d Vendors ", count );
6969}
6970
6971void ObjectMgr::LoadNpcTextId()
6972{
6973
6974    m_mCacheNpcTextIdMap.clear();
6975
6976    QueryResult* result = WorldDatabase.PQuery("SELECT npc_guid, textid FROM npc_gossip");
6977    if( !result )
6978    {
6979        barGoLink bar( 1 );
6980
6981        bar.step();
6982
6983        sLog.outString();
6984        sLog.outErrorDb(">> Loaded `npc_gossip`, table is empty!");
6985        return;
6986    }
6987
6988    barGoLink bar( result->GetRowCount() );
6989
6990    uint32 count = 0;
6991    uint32 guid,textid;
6992    do
6993    {
6994        bar.step();
6995
6996        Field* fields = result->Fetch();
6997
6998        guid   = fields[0].GetUInt32();
6999        textid = fields[1].GetUInt32();
7000
7001        if (!GetCreatureData(guid))
7002        {
7003            sLog.outErrorDb("Table `npc_gossip` have not existed creature (GUID: %u) entry, ignore. ",guid);
7004            continue;
7005        }
7006        if (!GetGossipText(textid))
7007        {
7008            sLog.outErrorDb("Table `npc_gossip` for creature (GUID: %u) have wrong Textid (%u), ignore. ", guid, textid);
7009            continue;
7010        }
7011
7012        m_mCacheNpcTextIdMap[guid] = textid ;
7013        ++count;
7014
7015    } while (result->NextRow());
7016    delete result;
7017
7018    sLog.outString();
7019    sLog.outString( ">> Loaded %d NpcTextId ", count );
7020}
7021
7022void ObjectMgr::AddVendorItem( uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 extendedcost, bool savetodb)
7023{
7024    VendorItemData& vList = m_mCacheVendorItemMap[entry];
7025    vList.AddItem(item,maxcount,incrtime,extendedcost);
7026
7027    if(savetodb) WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')",entry, item, maxcount,incrtime,extendedcost);
7028}
7029
7030bool ObjectMgr::RemoveVendorItem( uint32 entry,uint32 item, bool savetodb)
7031{
7032    CacheVendorItemMap::iterator  iter = m_mCacheVendorItemMap.find(entry);
7033    if(iter == m_mCacheVendorItemMap.end())
7034        return false;
7035
7036    if(!iter->second.FindItem(item))
7037        return false;
7038
7039    iter->second.RemoveItem(item);
7040    if(savetodb) WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item);
7041    return true;
7042}
7043
7044bool ObjectMgr::IsVendorItemValid( uint32 vendor_entry, uint32 item_id, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set<uint32>* skip_vendors, uint32 ORnpcflag ) const
7045{
7046    CreatureInfo const* cInfo = GetCreatureTemplate(vendor_entry);
7047    if(!cInfo)
7048    {
7049        if(pl)
7050            ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
7051        else
7052            sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not existed creature template (Entry: %u), ignore", vendor_entry);
7053        return false;
7054    }
7055
7056    if(!((cInfo->npcflag | ORnpcflag) & UNIT_NPC_FLAG_VENDOR))
7057    {
7058        if(!skip_vendors || skip_vendors->count(vendor_entry)==0)
7059        {
7060            if(pl)
7061                ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
7062            else
7063                sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not creature template (Entry: %u) without vendor flag, ignore", vendor_entry);
7064
7065            if(skip_vendors)
7066                skip_vendors->insert(vendor_entry);
7067        }
7068        return false;
7069    }
7070
7071    if(!GetItemPrototype(item_id))
7072    {
7073        if(pl)
7074            ChatHandler(pl).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id);
7075        else
7076            sLog.outErrorDb("Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore",vendor_entry,item_id);
7077        return false;
7078    }
7079
7080    if(ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost))
7081    {
7082        if(pl)
7083            ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST,ExtendedCost);
7084        else
7085            sLog.outErrorDb("Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore",item_id,ExtendedCost,vendor_entry);
7086        return false;
7087    }
7088
7089    if(maxcount > 0 && incrtime == 0)
7090    {
7091        if(pl)
7092            ChatHandler(pl).PSendSysMessage("MaxCount!=0 (%u) but IncrTime==0", maxcount);
7093        else
7094            sLog.outErrorDb( "Table `(game_event_)npc_vendor` has `maxcount` (%u) for item %u of vendor (Entry: %u) but `incrtime`=0, ignore", maxcount, item_id, vendor_entry);
7095        return false;
7096    }
7097    else if(maxcount==0 && incrtime > 0)
7098    {
7099        if(pl)
7100            ChatHandler(pl).PSendSysMessage("MaxCount==0 but IncrTime<>=0");
7101        else
7102            sLog.outErrorDb( "Table `(game_event_)npc_vendor` has `maxcount`=0 for item %u of vendor (Entry: %u) but `incrtime`<>0, ignore", item_id, vendor_entry);
7103        return false;
7104    }
7105
7106    VendorItemData const* vItems = GetNpcVendorItemList(vendor_entry);
7107    if(!vItems)
7108        return true;                                        // later checks for non-empty lists
7109
7110    if(vItems->FindItem(item_id))
7111    {
7112        if(pl)
7113            ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST,item_id);
7114        else
7115            sLog.outErrorDb( "Table `(game_event_)npc_vendor` has duplicate items %u for vendor (Entry: %u), ignore", item_id, vendor_entry);
7116        return false;
7117    }
7118
7119    if(vItems->GetItemCount() >= MAX_VENDOR_ITEMS)
7120    {
7121        if(pl)
7122            ChatHandler(pl).SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS);
7123        else
7124            sLog.outErrorDb( "Table `npc_vendor` has too many items (%u >= %i) for vendor (Entry: %u), ignore", vItems->GetItemCount(), MAX_VENDOR_ITEMS, vendor_entry);
7125        return false;
7126    }
7127
7128    return true;
7129}
7130
7131// Functions for scripting access
7132const char* GetAreaTriggerScriptNameById(uint32 id)
7133{
7134    return objmgr.GetAreaTriggerScriptName(id);
7135}
7136
7137bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value)
7138{
7139    if(start_value >= 0 || start_value <= end_value)        // start/end reversed for negative values
7140    {
7141        sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), use (%d - %d) instead.",table,start_value,end_value,-1,std::numeric_limits<int32>::min());
7142        start_value = -1;
7143        end_value = std::numeric_limits<int32>::min();
7144    }
7145
7146    // for scripting localized strings allowed use _only_ negative entries
7147    return objmgr.LoadTrinityStrings(db,table,end_value,start_value);
7148}
Note: See TracBrowser for help on using the browser.