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

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

[svn] * Implement honor rewards from quests - Source Mangos

Original author: KingPin?
Date: 2008-10-22 07:02:05-05:00

Line 
1/*
2 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
3 *
4 * Thanks to the original authors: MaNGOS <http://www.mangosproject.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        "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
2814    //   120            121
2815        "StartScript, CompleteScript"
2816        " FROM quest_template");
2817    if(result == NULL)
2818    {
2819        barGoLink bar( 1 );
2820        bar.step();
2821
2822        sLog.outString();
2823        sLog.outString( ">> Loaded 0 quests definitions" );
2824        sLog.outErrorDb("`quest_template` table is empty!");
2825        return;
2826    }
2827
2828    // create multimap previous quest for each existed quest
2829    // some quests can have many previous maps set by NextQuestId in previous quest
2830    // for example set of race quests can lead to single not race specific quest
2831    barGoLink bar( result->GetRowCount() );
2832    do
2833    {
2834        bar.step();
2835        Field *fields = result->Fetch();
2836
2837        Quest * newQuest = new Quest(fields);
2838        mQuestTemplates[newQuest->GetQuestId()] = newQuest;
2839    } while( result->NextRow() );
2840
2841    delete result;
2842
2843    // Post processing
2844    for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); iter++)
2845    {
2846        Quest * qinfo = iter->second;
2847
2848        // additional quest integrity checks (GO, creature_template and item_template must be loaded already)
2849
2850        if( qinfo->GetQuestMethod() >= 3 )
2851        {
2852            sLog.outErrorDb("Quest %u has `Method` = %u, expected values are 0, 1 or 2.",qinfo->GetQuestId(),qinfo->GetQuestMethod());
2853        }
2854
2855        if (qinfo->QuestFlags & ~QUEST_TRINITY_FLAGS_DB_ALLOWED)
2856        {
2857            sLog.outErrorDb("Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u",
2858                qinfo->GetQuestId(),qinfo->QuestFlags,QUEST_TRINITY_FLAGS_DB_ALLOWED >> 16);
2859            qinfo->QuestFlags &= QUEST_TRINITY_FLAGS_DB_ALLOWED;
2860        }
2861
2862        if(qinfo->QuestFlags & QUEST_FLAGS_DAILY)
2863        {
2864            if(!(qinfo->QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE))
2865            {
2866                sLog.outErrorDb("Daily Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId());
2867                qinfo->QuestFlags |= QUEST_TRINITY_FLAGS_REPEATABLE;
2868            }
2869        }
2870
2871        if(qinfo->QuestFlags & QUEST_FLAGS_AUTO_REWARDED)
2872        {
2873            // at auto-reward can be rewarded only RewChoiceItemId[0]
2874            for(int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j )
2875            {
2876                if(uint32 id = qinfo->RewChoiceItemId[j])
2877                {
2878                    sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item from `RewChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.",
2879                        qinfo->GetQuestId(),j+1,id,j+1);
2880                    // no changes, quest ignore this data
2881                }
2882            }
2883        }
2884
2885        // client quest log visual (area case)
2886        if( qinfo->ZoneOrSort > 0 )
2887        {
2888            if(!GetAreaEntryByAreaID(qinfo->ZoneOrSort))
2889            {
2890                sLog.outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
2891                    qinfo->GetQuestId(),qinfo->ZoneOrSort);
2892                // no changes, quest not dependent from this value but can have problems at client
2893            }
2894        }
2895        // client quest log visual (sort case)
2896        if( qinfo->ZoneOrSort < 0 )
2897        {
2898            QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort));
2899            if( !qSort )
2900            {
2901                sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.",
2902                    qinfo->GetQuestId(),qinfo->ZoneOrSort);
2903                // 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)
2904            }
2905            //check SkillOrClass value (class case).
2906            if( ClassByQuestSort(-int32(qinfo->ZoneOrSort)) )
2907            {
2908                // SkillOrClass should not have class case when class case already set in ZoneOrSort.
2909                if(qinfo->SkillOrClass < 0)
2910                {
2911                    sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClass` = %i (class case), redundant.",
2912                        qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClass);
2913                }
2914            }
2915            //check for proper SkillOrClass value (skill case)
2916            if(int32 skill_id =  SkillByQuestSort(-int32(qinfo->ZoneOrSort)))
2917            {
2918                // skill is positive value in SkillOrClass
2919                if(qinfo->SkillOrClass != skill_id )
2920                {
2921                    sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClass` does not have a corresponding value (%i).",
2922                        qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id);
2923                    //override, and force proper value here?
2924                }
2925            }
2926        }
2927
2928        // SkillOrClass (class case)
2929        if( qinfo->SkillOrClass < 0 )
2930        {
2931            if( !sChrClassesStore.LookupEntry(-int32(qinfo->SkillOrClass)) )
2932            {
2933                sLog.outErrorDb("Quest %u has `SkillOrClass` = %i (class case) but class (%i) does not exist",
2934                    qinfo->GetQuestId(),qinfo->SkillOrClass,-qinfo->SkillOrClass);
2935            }
2936        }
2937        // SkillOrClass (skill case)
2938        if( qinfo->SkillOrClass > 0 )
2939        {
2940            if( !sSkillLineStore.LookupEntry(qinfo->SkillOrClass) )
2941            {
2942                sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist",
2943                    qinfo->GetQuestId(),qinfo->SkillOrClass,qinfo->SkillOrClass);
2944            }
2945        }
2946
2947        if( qinfo->RequiredSkillValue )
2948        {
2949            if( qinfo->RequiredSkillValue > sWorld.GetConfigMaxSkillValue() )
2950            {
2951                sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but max possible skill is %u, quest can't be done.",
2952                    qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue());
2953                // no changes, quest can't be done for this requirement
2954            }
2955
2956            if( qinfo->SkillOrClass <= 0 )
2957            {
2958                sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.",
2959                    qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClass);
2960                // no changes, quest can't be done for this requirement (fail at wrong skill id)
2961            }
2962        }
2963        // else Skill quests can have 0 skill level, this is ok
2964
2965        if(qinfo->RepObjectiveFaction && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction))
2966        {
2967            sLog.outErrorDb("Quest %u has `RepObjectiveFaction` = %u but faction template %u does not exist, quest can't be done.",
2968                qinfo->GetQuestId(),qinfo->RepObjectiveFaction,qinfo->RepObjectiveFaction);
2969            // no changes, quest can't be done for this requirement
2970        }
2971
2972        if(qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction))
2973        {
2974            sLog.outErrorDb("Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.",
2975                qinfo->GetQuestId(),qinfo->RequiredMinRepFaction,qinfo->RequiredMinRepFaction);
2976            // no changes, quest can't be done for this requirement
2977        }
2978
2979        if(qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction))
2980        {
2981            sLog.outErrorDb("Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.",
2982                qinfo->GetQuestId(),qinfo->RequiredMaxRepFaction,qinfo->RequiredMaxRepFaction);
2983            // no changes, quest can't be done for this requirement
2984        }
2985
2986        if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > Player::Reputation_Cap)
2987        {
2988            sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.",
2989                qinfo->GetQuestId(),qinfo->RequiredMinRepValue,Player::Reputation_Cap);
2990            // no changes, quest can't be done for this requirement
2991        }
2992
2993        if(qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue)
2994        {
2995            sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.",
2996                qinfo->GetQuestId(),qinfo->RequiredMaxRepValue,qinfo->RequiredMinRepValue);
2997            // no changes, quest can't be done for this requirement
2998        }
2999
3000        if(!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0 )
3001        {
3002            sLog.outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect",
3003                qinfo->GetQuestId(),qinfo->RepObjectiveValue);
3004            // warning
3005        }
3006
3007        if(!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0 )
3008        {
3009            sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect",
3010                qinfo->GetQuestId(),qinfo->RequiredMinRepValue);
3011            // warning
3012        }
3013
3014        if(!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0 )
3015        {
3016            sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect",
3017                qinfo->GetQuestId(),qinfo->RequiredMaxRepValue);
3018            // warning
3019        }
3020
3021        if(qinfo->CharTitleId && !sCharTitlesStore.LookupEntry(qinfo->CharTitleId))
3022        {
3023            sLog.outErrorDb("Quest %u has `CharTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.",
3024                qinfo->GetQuestId(),qinfo->GetCharTitleId(),qinfo->GetCharTitleId());
3025            qinfo->CharTitleId = 0;
3026            // quest can't reward this title
3027        }
3028
3029        if(qinfo->SrcItemId)
3030        {
3031            if(!sItemStorage.LookupEntry<ItemPrototype>(qinfo->SrcItemId))
3032            {
3033                sLog.outErrorDb("Quest %u has `SrcItemId` = %u but item with entry %u does not exist, quest can't be done.",
3034                    qinfo->GetQuestId(),qinfo->SrcItemId,qinfo->SrcItemId);
3035                qinfo->SrcItemId = 0;                       // quest can't be done for this requirement
3036            }
3037            else if(qinfo->SrcItemCount==0)
3038            {
3039                sLog.outErrorDb("Quest %u has `SrcItemId` = %u but `SrcItemCount` = 0, set to 1 but need fix in DB.",
3040                    qinfo->GetQuestId(),qinfo->SrcItemId);
3041                qinfo->SrcItemCount = 1;                    // update to 1 for allow quest work for backward comptibility with DB
3042            }
3043        }
3044        else if(qinfo->SrcItemCount>0)
3045        {
3046            sLog.outErrorDb("Quest %u has `SrcItemId` = 0 but `SrcItemCount` = %u, useless value.",
3047                qinfo->GetQuestId(),qinfo->SrcItemCount);
3048            qinfo->SrcItemCount=0;                          // no quest work changes in fact
3049        }
3050
3051        if(qinfo->SrcSpell)
3052        {
3053            SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->SrcSpell);
3054            if(!spellInfo)
3055            {
3056                sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u doesn't exist, quest can't be done.",
3057                    qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell);
3058                qinfo->SrcSpell = 0;                        // quest can't be done for this requirement
3059            }
3060            else if(!SpellMgr::IsSpellValid(spellInfo))
3061            {
3062                sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u is broken, quest can't be done.",
3063                    qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell);
3064                qinfo->SrcSpell = 0;                        // quest can't be done for this requirement
3065            }
3066        }
3067
3068        for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
3069        {
3070            uint32 id = qinfo->ReqItemId[j];
3071            if(id)
3072            {
3073                if(qinfo->ReqItemCount[j]==0)
3074                {
3075                    sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but `ReqItemCount%d` = 0, quest can't be done.",
3076                        qinfo->GetQuestId(),j+1,id,j+1);
3077                    // no changes, quest can't be done for this requirement
3078                }
3079
3080                qinfo->SetFlag(QUEST_TRINITY_FLAGS_DELIVER);
3081
3082                if(!sItemStorage.LookupEntry<ItemPrototype>(id))
3083                {
3084                    sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but item with entry %u does not exist, quest can't be done.",
3085                        qinfo->GetQuestId(),j+1,id,id);
3086                    qinfo->ReqItemCount[j] = 0;             // prevent incorrect work of quest
3087                }
3088            }
3089            else if(qinfo->ReqItemCount[j]>0)
3090            {
3091                sLog.outErrorDb("Quest %u has `ReqItemId%d` = 0 but `ReqItemCount%d` = %u, quest can't be done.",
3092                    qinfo->GetQuestId(),j+1,j+1,qinfo->ReqItemCount[j]);
3093                qinfo->ReqItemCount[j] = 0;                 // prevent incorrect work of quest
3094            }
3095        }
3096
3097        for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
3098        {
3099            uint32 id = qinfo->ReqSourceId[j];
3100            if(id)
3101            {
3102                if(!sItemStorage.LookupEntry<ItemPrototype>(id))
3103                {
3104                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but item with entry %u does not exist, quest can't be done.",
3105                        qinfo->GetQuestId(),j+1,id,id);
3106                    // no changes, quest can't be done for this requirement
3107                }
3108
3109                if(!qinfo->ReqSourceCount[j])
3110                {
3111                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.",
3112                        qinfo->GetQuestId(),j+1,id,j+1);
3113                    qinfo->ReqSourceId[j] = 0;              // prevent incorrect work of quest
3114                }
3115
3116                if(!qinfo->ReqSourceRef[j])
3117                {
3118                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.",
3119                        qinfo->GetQuestId(),j+1,id,j+1);
3120                    qinfo->ReqSourceId[j] = 0;              // prevent incorrect work of quest
3121                }
3122            }
3123            else
3124            {
3125                if(qinfo->ReqSourceCount[j]>0)
3126                {
3127                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceCount%d` = %u.",
3128                        qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]);
3129                    // no changes, quest ignore this data
3130                }
3131
3132                if(qinfo->ReqSourceRef[j]>0)
3133                {
3134                    sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.",
3135                        qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]);
3136                    // no changes, quest ignore this data
3137                }
3138            }
3139        }
3140
3141        for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
3142        {
3143            uint32 ref = qinfo->ReqSourceRef[j];
3144            if(ref)
3145            {
3146                if(ref > QUEST_OBJECTIVES_COUNT)
3147                {
3148                    sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.",
3149                        qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT);
3150                    // no changes, quest can't be done for this requirement
3151                }
3152                else
3153                if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1])
3154                {
3155                    sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.",
3156                        qinfo->GetQuestId(),j+1,ref,ref,ref);
3157                    // no changes, quest can't be done for this requirement
3158                }
3159                else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1])
3160                {
3161                    sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.",
3162                        qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]);
3163                    // no changes, quest can't be done for this requirement
3164                    qinfo->ReqSourceId[j] = 0;              // prevent incorrect work of quest
3165                }
3166            }
3167        }
3168
3169        for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
3170        {
3171            uint32 id = qinfo->ReqSpell[j];
3172            if(id)
3173            {
3174                SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
3175                if(!spellInfo)
3176                {
3177                    sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.",
3178                        qinfo->GetQuestId(),j+1,id,id);
3179                    // no changes, quest can't be done for this requirement
3180                }
3181
3182                if(!qinfo->ReqCreatureOrGOId[j])
3183                {
3184                    bool found = false;
3185                    for(int k = 0; k < 3; ++k)
3186                    {
3187                        if( spellInfo->Effect[k]==SPELL_EFFECT_QUEST_COMPLETE && uint32(spellInfo->EffectMiscValue[k])==qinfo->QuestId ||
3188                            spellInfo->Effect[k]==SPELL_EFFECT_SEND_EVENT)
3189                        {
3190                            found = true;
3191                            break;
3192                        }
3193                    }
3194
3195                    if(found)
3196                    {
3197                        if(!qinfo->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
3198                        {
3199                            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);
3200
3201                            // this will prevent quest completing without objective
3202                            const_cast<Quest*>(qinfo)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
3203                        }
3204                    }
3205                    else
3206                    {
3207                        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.",
3208                            qinfo->GetQuestId(),j+1,id,j+1,id);
3209                        // no changes, quest can't be done for this requirement
3210                    }
3211                }
3212            }
3213        }
3214
3215        for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
3216        {
3217            int32 id = qinfo->ReqCreatureOrGOId[j];
3218            if(id < 0 && !sGOStorage.LookupEntry<GameObjectInfo>(-id))
3219            {
3220                sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but gameobject %u does not exist, quest can't be done.",
3221                    qinfo->GetQuestId(),j+1,id,uint32(-id));
3222                qinfo->ReqCreatureOrGOId[j] = 0;            // quest can't be done for this requirement
3223            }
3224
3225            if(id > 0 && !sCreatureStorage.LookupEntry<CreatureInfo>(id))
3226            {
3227                sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but creature with entry %u does not exist, quest can't be done.",
3228                    qinfo->GetQuestId(),j+1,id,uint32(id));
3229                qinfo->ReqCreatureOrGOId[j] = 0;            // quest can't be done for this requirement
3230            }
3231
3232            if(id)
3233            {
3234                // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast
3235
3236                qinfo->SetFlag(QUEST_TRINITY_FLAGS_KILL_OR_CAST | QUEST_TRINITY_FLAGS_SPEAKTO);
3237
3238                if(!qinfo->ReqCreatureOrGOCount[j])
3239                {
3240                    sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %u but `ReqCreatureOrGOCount%d` = 0, quest can't be done.",
3241                        qinfo->GetQuestId(),j+1,id,j+1);
3242                    // no changes, quest can be incorrectly done, but we already report this
3243                }
3244            }
3245            else if(qinfo->ReqCreatureOrGOCount[j]>0)
3246            {
3247                sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = 0 but `ReqCreatureOrGOCount%d` = %u.",
3248                    qinfo->GetQuestId(),j+1,j+1,qinfo->ReqCreatureOrGOCount[j]);
3249                // no changes, quest ignore this data
3250            }
3251        }
3252
3253        for(int j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j )
3254        {
3255            uint32 id = qinfo->RewChoiceItemId[j];
3256            if(id)
3257            {
3258                if(!sItemStorage.LookupEntry<ItemPrototype>(id))
3259                {
3260                    sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
3261                        qinfo->GetQuestId(),j+1,id,id);
3262                    qinfo->RewChoiceItemId[j] = 0;          // no changes, quest will not reward this
3263                }
3264
3265                if(!qinfo->RewChoiceItemCount[j])
3266                {
3267                    sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but `RewChoiceItemCount%d` = 0, quest can't be done.",
3268                        qinfo->GetQuestId(),j+1,id,j+1);
3269                    // no changes, quest can't be done
3270                }
3271            }
3272            else if(qinfo->RewChoiceItemCount[j]>0)
3273            {
3274                sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = 0 but `RewChoiceItemCount%d` = %u.",
3275                    qinfo->GetQuestId(),j+1,j+1,qinfo->RewChoiceItemCount[j]);
3276                // no changes, quest ignore this data
3277            }
3278        }
3279
3280        for(int j = 0; j < QUEST_REWARDS_COUNT; ++j )
3281        {
3282            uint32 id = qinfo->RewItemId[j];
3283            if(id)
3284            {
3285                if(!sItemStorage.LookupEntry<ItemPrototype>(id))
3286                {
3287                    sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
3288                        qinfo->GetQuestId(),j+1,id,id);
3289                    qinfo->RewItemId[j] = 0;                // no changes, quest will not reward this item
3290                }
3291
3292                if(!qinfo->RewItemCount[j])
3293                {
3294                    sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but `RewItemCount%d` = 0, quest will not reward this item.",
3295                        qinfo->GetQuestId(),j+1,id,j+1);
3296                    // no changes
3297                }
3298            }
3299            else if(qinfo->RewItemCount[j]>0)
3300            {
3301                sLog.outErrorDb("Quest %u has `RewItemId%d` = 0 but `RewItemCount%d` = %u.",
3302                    qinfo->GetQuestId(),j+1,j+1,qinfo->RewItemCount[j]);
3303                // no changes, quest ignore this data
3304            }
3305        }
3306
3307        for(int j = 0; j < QUEST_REPUTATIONS_COUNT; ++j)
3308        {
3309            if(qinfo->RewRepFaction[j])
3310            {
3311                if(!qinfo->RewRepValue[j])
3312                {
3313                    sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but `RewRepValue%d` = 0, quest will not reward this reputation.",
3314                        qinfo->GetQuestId(),j+1,qinfo->RewRepValue[j],j+1);
3315                    // no changes
3316                }
3317
3318                if(!sFactionStore.LookupEntry(qinfo->RewRepFaction[j]))
3319                {
3320                    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.",
3321                        qinfo->GetQuestId(),j+1,qinfo->RewRepFaction[j] ,qinfo->RewRepFaction[j] );
3322                    qinfo->RewRepFaction[j] = 0;            // quest will not reward this
3323                }
3324            }
3325            else if(qinfo->RewRepValue[j]!=0)
3326            {
3327                sLog.outErrorDb("Quest %u has `RewRepFaction%d` = 0 but `RewRepValue%d` = %u.",
3328                    qinfo->GetQuestId(),j+1,j+1,qinfo->RewRepValue[j]);
3329                // no changes, quest ignore this data
3330            }
3331        }
3332
3333        if(qinfo->RewSpell)
3334        {
3335            SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpell);
3336
3337            if(!spellInfo)
3338            {
3339                sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u does not exist, spell removed as display reward.",
3340                    qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
3341                qinfo->RewSpell = 0;                        // no spell reward will display for this quest
3342            }
3343
3344            else if(!SpellMgr::IsSpellValid(spellInfo))
3345            {
3346                sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.",
3347                    qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
3348                qinfo->RewSpell = 0;                        // no spell reward will display for this quest
3349            }
3350
3351        }
3352
3353        if(qinfo->RewSpellCast)
3354        {
3355            SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpellCast);
3356
3357            if(!spellInfo)
3358            {
3359                sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.",
3360                    qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
3361                qinfo->RewSpellCast = 0;                    // no spell will be casted on player
3362            }
3363
3364            else if(!SpellMgr::IsSpellValid(spellInfo))
3365            {
3366                sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.",
3367                    qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
3368                qinfo->RewSpellCast = 0;                    // no spell will be casted on player
3369            }
3370
3371        }
3372
3373        if(qinfo->RewMailTemplateId)
3374        {
3375            if(!sMailTemplateStore.LookupEntry(qinfo->RewMailTemplateId))
3376            {
3377                sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template  %u does not exist, quest will not have a mail reward.",
3378                    qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId);
3379                qinfo->RewMailTemplateId = 0;               // no mail will send to player
3380                qinfo->RewMailDelaySecs = 0;                // no mail will send to player
3381            }
3382        }
3383
3384        if(qinfo->NextQuestInChain)
3385        {
3386            if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end())
3387            {
3388                sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.",
3389                    qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain );
3390                qinfo->NextQuestInChain = 0;
3391            }
3392            else
3393                mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId());
3394        }
3395
3396        // fill additional data stores
3397        if(qinfo->PrevQuestId)
3398        {
3399            if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end())
3400            {
3401                sLog.outErrorDb("Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId());
3402            }
3403            else
3404            {
3405                qinfo->prevQuests.push_back(qinfo->PrevQuestId);
3406            }
3407        }
3408
3409        if(qinfo->NextQuestId)
3410        {
3411            if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end())
3412            {
3413                sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
3414            }
3415            else
3416            {
3417                int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
3418                mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId);
3419            }
3420        }
3421
3422        if(qinfo->ExclusiveGroup)
3423            mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId()));
3424        if(qinfo->LimitTime)
3425            qinfo->SetFlag(QUEST_TRINITY_FLAGS_TIMED);
3426    }
3427
3428    // check QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
3429    for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i)
3430    {
3431        SpellEntry const *spellInfo = sSpellStore.LookupEntry(i);
3432        if(!spellInfo)
3433            continue;
3434
3435        for(int j = 0; j < 3; ++j)
3436        {
3437            if(spellInfo->Effect[j] != SPELL_EFFECT_QUEST_COMPLETE)
3438                continue;
3439
3440            uint32 quest_id = spellInfo->EffectMiscValue[j];
3441
3442            Quest const* quest = GetQuestTemplate(quest_id);
3443
3444            // some quest referenced in spells not exist (outdataed spells)
3445            if(!quest)
3446                continue;
3447
3448            if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
3449            {
3450                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);
3451
3452                // this will prevent quest completing without objective
3453                const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
3454            }
3455        }
3456    }
3457
3458    sLog.outString();
3459    sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() );
3460}
3461
3462void ObjectMgr::LoadQuestLocales()
3463{
3464    mQuestLocaleMap.clear();
3465
3466    QueryResult *result = WorldDatabase.Query("SELECT entry,"
3467        "Title_loc1,Details_loc1,Objectives_loc1,OfferRewardText_loc1,RequestItemsText_loc1,EndText_loc1,ObjectiveText1_loc1,ObjectiveText2_loc1,ObjectiveText3_loc1,ObjectiveText4_loc1,"
3468        "Title_loc2,Details_loc2,Objectives_loc2,OfferRewardText_loc2,RequestItemsText_loc2,EndText_loc2,ObjectiveText1_loc2,ObjectiveText2_loc2,ObjectiveText3_loc2,ObjectiveText4_loc2,"
3469        "Title_loc3,Details_loc3,Objectives_loc3,OfferRewardText_loc3,RequestItemsText_loc3,EndText_loc3,ObjectiveText1_loc3,ObjectiveText2_loc3,ObjectiveText3_loc3,ObjectiveText4_loc3,"
3470        "Title_loc4,Details_loc4,Objectives_loc4,OfferRewardText_loc4,RequestItemsText_loc4,EndText_loc4,ObjectiveText1_loc4,ObjectiveText2_loc4,ObjectiveText3_loc4,ObjectiveText4_loc4,"
3471        "Title_loc5,Details_loc5,Objectives_loc5,OfferRewardText_loc5,RequestItemsText_loc5,EndText_loc5,ObjectiveText1_loc5,ObjectiveText2_loc5,ObjectiveText3_loc5,ObjectiveText4_loc5,"
3472        "Title_loc6,Details_loc6,Objectives_loc6,OfferRewardText_loc6,RequestItemsText_loc6,EndText_loc6,ObjectiveText1_loc6,ObjectiveText2_loc6,ObjectiveText3_loc6,ObjectiveText4_loc6,"
3473        "Title_loc7,Details_loc7,Objectives_loc7,OfferRewardText_loc7,RequestItemsText_loc7,EndText_loc7,ObjectiveText1_loc7,ObjectiveText2_loc7,ObjectiveText3_loc7,ObjectiveText4_loc7,"
3474        "Title_loc8,Details_loc8,Objectives_loc8,OfferRewardText_loc8,RequestItemsText_loc8,EndText_loc8,ObjectiveText1_loc8,ObjectiveText2_loc8,ObjectiveText3_loc8,ObjectiveText4_loc8"
3475        " FROM locales_quest"
3476        );
3477
3478    if(!result)
3479    {
3480        barGoLink bar(1);
3481
3482        bar.step();
3483
3484        sLog.outString("");
3485        sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty.");
3486        return;
3487    }
3488
3489    barGoLink bar(result->GetRowCount());
3490
3491    do
3492    {
3493        Field *fields = result->Fetch();
3494        bar.step();
3495
3496        uint32 entry = fields[0].GetUInt32();
3497
3498        QuestLocale& data = mQuestLocaleMap[entry];
3499
3500        for(int i = 1; i < MAX_LOCALE; ++i)
3501        {
3502            std::string str = fields[1+10*(i-1)].GetCppString();
3503            if(!str.empty())
3504            {
3505                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3506                if(idx >= 0)
3507                {
3508                    if(data.Title.size() <= idx)
3509                        data.Title.resize(idx+1);
3510
3511                    data.Title[idx] = str;
3512                }
3513            }
3514            str = fields[1+10*(i-1)+1].GetCppString();
3515            if(!str.empty())
3516            {
3517                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3518                if(idx >= 0)
3519                {
3520                    if(data.Details.size() <= idx)
3521                        data.Details.resize(idx+1);
3522
3523                    data.Details[idx] = str;
3524                }
3525            }
3526            str = fields[1+10*(i-1)+2].GetCppString();
3527            if(!str.empty())
3528            {
3529                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3530                if(idx >= 0)
3531                {
3532                    if(data.Objectives.size() <= idx)
3533                        data.Objectives.resize(idx+1);
3534
3535                    data.Objectives[idx] = str;
3536                }
3537            }
3538            str = fields[1+10*(i-1)+3].GetCppString();
3539            if(!str.empty())
3540            {
3541                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3542                if(idx >= 0)
3543                {
3544                    if(data.OfferRewardText.size() <= idx)
3545                        data.OfferRewardText.resize(idx+1);
3546
3547                    data.OfferRewardText[idx] = str;
3548                }
3549            }
3550            str = fields[1+10*(i-1)+4].GetCppString();
3551            if(!str.empty())
3552            {
3553                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3554                if(idx >= 0)
3555                {
3556                    if(data.RequestItemsText.size() <= idx)
3557                        data.RequestItemsText.resize(idx+1);
3558
3559                    data.RequestItemsText[idx] = str;
3560                }
3561            }
3562            str = fields[1+10*(i-1)+5].GetCppString();
3563            if(!str.empty())
3564            {
3565                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3566                if(idx >= 0)
3567                {
3568                    if(data.EndText.size() <= idx)
3569                        data.EndText.resize(idx+1);
3570
3571                    data.EndText[idx] = str;
3572                }
3573            }
3574            for(int k = 0; k < 4; ++k)
3575            {
3576                str = fields[1+10*(i-1)+6+k].GetCppString();
3577                if(!str.empty())
3578                {
3579                    int idx = GetOrNewIndexForLocale(LocaleConstant(i));
3580                    if(idx >= 0)
3581                    {
3582                        if(data.ObjectiveText[k].size() <= idx)
3583                            data.ObjectiveText[k].resize(idx+1);
3584
3585                        data.ObjectiveText[k][idx] = str;
3586                    }
3587                }
3588            }
3589        }
3590    } while (result->NextRow());
3591
3592    delete result;
3593
3594    sLog.outString();
3595    sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() );
3596}
3597
3598void ObjectMgr::LoadPetCreateSpells()
3599{
3600    QueryResult *result = WorldDatabase.PQuery("SELECT entry, Spell1, Spell2, Spell3, Spell4 FROM petcreateinfo_spell");
3601    if(!result)
3602    {
3603        barGoLink bar( 1 );
3604        bar.step();
3605
3606        sLog.outString();
3607        sLog.outString( ">> Loaded 0 pet create spells" );
3608        sLog.outErrorDb("`petcreateinfo_spell` table is empty!");
3609        return;
3610    }
3611
3612    uint32 count = 0;
3613
3614    barGoLink bar( result->GetRowCount() );
3615
3616    mPetCreateSpell.clear();
3617
3618    do
3619    {
3620        Field *fields = result->Fetch();
3621        bar.step();
3622
3623        uint32 creature_id = fields[0].GetUInt32();
3624
3625        if(!creature_id || !sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
3626            continue;
3627
3628        PetCreateSpellEntry PetCreateSpell;
3629        for(int i = 0; i < 4; i++)
3630        {
3631            PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32();
3632
3633            if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i]))
3634                sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]);
3635        }
3636
3637        mPetCreateSpell[creature_id] = PetCreateSpell;
3638
3639        ++count;
3640    }
3641    while (result->NextRow());
3642
3643    delete result;
3644
3645    sLog.outString();
3646    sLog.outString( ">> Loaded %u pet create spells", count );
3647}
3648
3649void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
3650{
3651    if(sWorld.IsScriptScheduled())                          // function don't must be called in time scripts use.
3652        return;
3653
3654    sLog.outString( "%s :", tablename);
3655
3656    scripts.clear();                                        // need for reload support
3657
3658    QueryResult *result = WorldDatabase.PQuery( "SELECT id,delay,command,datalong,datalong2,datatext, x, y, z, o FROM %s", tablename );
3659
3660    uint32 count = 0;
3661
3662    if( !result )
3663    {
3664        barGoLink bar( 1 );
3665        bar.step();
3666
3667        sLog.outString();
3668        sLog.outString( ">> Loaded %u script definitions", count );
3669        return;
3670    }
3671
3672    barGoLink bar( result->GetRowCount() );
3673
3674    do
3675    {
3676        bar.step();
3677
3678        Field *fields = result->Fetch();
3679        ScriptInfo tmp;
3680        tmp.id = fields[0].GetUInt32();
3681        tmp.delay = fields[1].GetUInt32();
3682        tmp.command = fields[2].GetUInt32();
3683        tmp.datalong = fields[3].GetUInt32();
3684        tmp.datalong2 = fields[4].GetUInt32();
3685        tmp.datatext = fields[5].GetCppString();
3686        tmp.x = fields[6].GetFloat();
3687        tmp.y = fields[7].GetFloat();
3688        tmp.z = fields[8].GetFloat();
3689        tmp.o = fields[9].GetFloat();
3690
3691        // generic command args check
3692        switch(tmp.command)
3693        {
3694            case SCRIPT_COMMAND_TALK:
3695            {
3696                if(tmp.datalong > 3)
3697                {
3698                    sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id);
3699                    continue;
3700                }
3701                break;
3702            }
3703
3704            case SCRIPT_COMMAND_TELEPORT_TO:
3705            {
3706                if(!sMapStore.LookupEntry(tmp.datalong))
3707                {
3708                    sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.datalong,tmp.id);
3709                    continue;
3710                }
3711
3712                if(!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
3713                {
3714                    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);
3715                    continue;
3716                }
3717                break;
3718            }
3719
3720            case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
3721            {
3722                if(!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
3723                {
3724                    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);
3725                    continue;
3726                }
3727
3728                if(!GetCreatureTemplate(tmp.datalong))
3729                {
3730                    sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.datalong,tmp.id);
3731                    continue;
3732                }
3733                break;
3734            }
3735
3736            case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
3737            {
3738                GameObjectData const* data = GetGOData(tmp.datalong);
3739                if(!data)
3740                {
3741                    sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,tmp.id);
3742                    continue;
3743                }
3744
3745                GameObjectInfo const* info = GetGameObjectInfo(data->id);
3746                if(!info)
3747                {
3748                    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);
3749                    continue;
3750                }
3751
3752                if( info->type==GAMEOBJECT_TYPE_FISHINGNODE ||
3753                    info->type==GAMEOBJECT_TYPE_FISHINGHOLE ||
3754                    info->type==GAMEOBJECT_TYPE_DOOR        ||
3755                    info->type==GAMEOBJECT_TYPE_BUTTON      ||
3756                    info->type==GAMEOBJECT_TYPE_TRAP )
3757                {
3758                    sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,info->id,tmp.id);
3759                    continue;
3760                }
3761                break;
3762            }
3763            case SCRIPT_COMMAND_OPEN_DOOR:
3764            case SCRIPT_COMMAND_CLOSE_DOOR:
3765            {
3766                GameObjectData const* data = GetGOData(tmp.datalong);
3767                if(!data)
3768                {
3769                    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);
3770                    continue;
3771                }
3772
3773                GameObjectInfo const* info = GetGameObjectInfo(data->id);
3774                if(!info)
3775                {
3776                    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);
3777                    continue;
3778                }
3779
3780                if( info->type!=GAMEOBJECT_TYPE_DOOR)
3781                {
3782                    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);
3783                    continue;
3784                }
3785
3786                break;
3787            }
3788            case SCRIPT_COMMAND_QUEST_EXPLORED:
3789            {
3790                Quest const* quest = GetQuestTemplate(tmp.datalong);
3791                if(!quest)
3792                {
3793                    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);
3794                    continue;
3795                }
3796
3797                if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
3798                {
3799                    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);
3800
3801                    // this will prevent quest completing without objective
3802                    const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
3803
3804                    // continue; - quest objective requiremet set and command can be allowed
3805                }
3806
3807                if(float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
3808                {
3809                    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);
3810                    continue;
3811                }
3812
3813                if(tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
3814                {
3815                    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));
3816                    continue;
3817                }
3818
3819                if(tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE)
3820                {
3821                    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));
3822                    continue;
3823                }
3824
3825                break;
3826            }
3827
3828            case SCRIPT_COMMAND_REMOVE_AURA:
3829            case SCRIPT_COMMAND_CAST_SPELL:
3830            {
3831                if(!sSpellStore.LookupEntry(tmp.datalong))
3832                {
3833                    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);
3834                    continue;
3835                }
3836                break;
3837            }
3838        }
3839
3840        if (scripts.find(tmp.id) == scripts.end())
3841        {
3842            ScriptMap emptyMap;
3843            scripts[tmp.id] = emptyMap;
3844        }
3845        scripts[tmp.id].insert(std::pair<uint32, ScriptInfo>(tmp.delay, tmp));
3846
3847        ++count;
3848    } while( result->NextRow() );
3849
3850    delete result;
3851
3852    sLog.outString();
3853    sLog.outString( ">> Loaded %u script definitions", count );
3854}
3855
3856void ObjectMgr::LoadGameObjectScripts()
3857{
3858    LoadScripts(sGameObjectScripts,    "gameobject_scripts");
3859
3860    // check ids
3861    for(ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr)
3862    {
3863        if(!GetGOData(itr->first))
3864            sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id",itr->first);
3865    }
3866}
3867
3868void ObjectMgr::LoadQuestEndScripts()
3869{
3870    LoadScripts(sQuestEndScripts,  "quest_end_scripts");
3871
3872    // check ids
3873    for(ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr)
3874    {
3875        if(!GetQuestTemplate(itr->first))
3876            sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id",itr->first);
3877    }
3878}
3879
3880void ObjectMgr::LoadQuestStartScripts()
3881{
3882    LoadScripts(sQuestStartScripts,"quest_start_scripts");
3883
3884    // check ids
3885    for(ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr)
3886    {
3887        if(!GetQuestTemplate(itr->first))
3888            sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id",itr->first);
3889    }
3890}
3891
3892void ObjectMgr::LoadSpellScripts()
3893{
3894    LoadScripts(sSpellScripts, "spell_scripts");
3895
3896    // check ids
3897    for(ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr)
3898    {
3899        SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
3900
3901        if(!spellInfo)
3902        {
3903            sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id",itr->first);
3904            continue;
3905        }
3906
3907        //check for correct spellEffect
3908        bool found = false;
3909        for(int i=0; i<3; ++i)
3910        {
3911            // skip empty effects
3912            if( !spellInfo->Effect[i] )
3913                continue;
3914
3915            if( spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT )
3916            {
3917                found =  true;
3918                break;
3919            }
3920        }
3921
3922        if(!found)
3923            sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect",itr->first,SPELL_EFFECT_SCRIPT_EFFECT);
3924    }
3925}
3926
3927void ObjectMgr::LoadEventScripts()
3928{
3929    LoadScripts(sEventScripts, "event_scripts");
3930
3931    std::set<uint32> evt_scripts;
3932    // Load all possible script entries from gameobjects
3933    for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
3934    {
3935        GameObjectInfo const * goInfo = sGOStorage.LookupEntry<GameObjectInfo>(i);
3936        if (goInfo)
3937        {
3938            switch(goInfo->type)
3939            {
3940                case GAMEOBJECT_TYPE_GOOBER:
3941                    if(goInfo->goober.eventId)
3942                        evt_scripts.insert(goInfo->goober.eventId);
3943                    break;
3944                case GAMEOBJECT_TYPE_CHEST:
3945                    if(goInfo->chest.eventId)
3946                        evt_scripts.insert(goInfo->chest.eventId);
3947                    break;
3948                default:
3949                    break;
3950            }
3951        }
3952    }
3953    // Load all possible script entries from spells
3954    for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
3955    {
3956        SpellEntry const * spell = sSpellStore.LookupEntry(i);
3957        if (spell)
3958        {
3959            for(int j=0; j<3; ++j)
3960            {
3961                if( spell->Effect[j] == SPELL_EFFECT_SEND_EVENT )
3962                {
3963                    if (spell->EffectMiscValue[j])
3964                        evt_scripts.insert(spell->EffectMiscValue[j]);
3965                }
3966            }
3967        }
3968    }
3969    // Then check if all scripts are in above list of possible script entries
3970    for(ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr)
3971    {
3972        std::set<uint32>::const_iterator itr2 = evt_scripts.find(itr->first);
3973        if (itr2 == evt_scripts.end())
3974            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);
3975    }
3976}
3977
3978void ObjectMgr::LoadItemTexts()
3979{
3980    QueryResult *result = CharacterDatabase.PQuery("SELECT id, text FROM item_text");
3981
3982    uint32 count = 0;
3983
3984    if( !result )
3985    {
3986        barGoLink bar( 1 );
3987        bar.step();
3988
3989        sLog.outString();
3990        sLog.outString( ">> Loaded %u item pages", count );
3991        return;
3992    }
3993
3994    barGoLink bar( result->GetRowCount() );
3995
3996    Field* fields;
3997    do
3998    {
3999        bar.step();
4000
4001        fields = result->Fetch();
4002
4003        mItemTexts[ fields[0].GetUInt32() ] = fields[1].GetCppString();
4004
4005        ++count;
4006
4007    } while ( result->NextRow() );
4008
4009    delete result;
4010
4011    sLog.outString();
4012    sLog.outString( ">> Loaded %u item texts", count );
4013}
4014
4015void ObjectMgr::LoadPageTexts()
4016{
4017    sPageTextStore.Free();                                  // for reload case
4018
4019    sPageTextStore.Load();
4020    sLog.outString( ">> Loaded %u page texts", sPageTextStore.RecordCount );
4021    sLog.outString();
4022
4023    for(uint32 i = 1; i < sPageTextStore.MaxEntry; ++i)
4024    {
4025        // check data correctness
4026        PageText const* page = sPageTextStore.LookupEntry<PageText>(i);
4027        if(!page)
4028            continue;
4029
4030        if(page->Next_Page && !sPageTextStore.LookupEntry<PageText>(page->Next_Page))
4031        {
4032            sLog.outErrorDb("Page text (Id: %u) has not existing next page (Id:%u)", i,page->Next_Page);
4033            continue;
4034        }
4035
4036        // detect circular reference
4037        std::set<uint32> checkedPages;
4038        for(PageText const* pageItr = page; pageItr; pageItr = sPageTextStore.LookupEntry<PageText>(pageItr->Next_Page))
4039        {
4040            if(!pageItr->Next_Page)
4041                break;
4042            checkedPages.insert(pageItr->Page_ID);
4043            if(checkedPages.find(pageItr->Next_Page)!=checkedPages.end())
4044            {
4045                std::ostringstream ss;
4046                ss<< "The text page(s) ";
4047                for (std::set<uint32>::iterator itr= checkedPages.begin();itr!=checkedPages.end(); itr++)
4048                    ss << *itr << " ";
4049                ss << "create(s) a circular reference, which can cause the server to freeze. Changing Next_Page of page "
4050                    << pageItr->Page_ID <<" to 0";
4051                sLog.outErrorDb(ss.str().c_str());
4052                const_cast<PageText*>(pageItr)->Next_Page = 0;
4053                break;
4054            }
4055        }
4056    }
4057}
4058
4059void ObjectMgr::LoadPageTextLocales()
4060{
4061    mPageTextLocaleMap.clear();
4062   
4063    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");
4064
4065    if(!result)
4066    {
4067        barGoLink bar(1);
4068
4069        bar.step();
4070
4071        sLog.outString("");
4072        sLog.outString(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty.");
4073        return;
4074    }
4075
4076    barGoLink bar(result->GetRowCount());
4077
4078    do
4079    {
4080        Field *fields = result->Fetch();
4081        bar.step();
4082
4083        uint32 entry = fields[0].GetUInt32();
4084
4085        PageTextLocale& data = mPageTextLocaleMap[entry];
4086
4087        for(int i = 1; i < MAX_LOCALE; ++i)
4088        {
4089            std::string str = fields[i].GetCppString();
4090            if(str.empty())
4091                continue;
4092
4093            int idx = GetOrNewIndexForLocale(LocaleConstant(i));
4094            if(idx >= 0)
4095            {
4096                if(data.Text.size() <= idx)
4097                    data.Text.resize(idx+1);
4098
4099                data.Text[idx] = str;
4100            }
4101        }
4102
4103    } while (result->NextRow());
4104
4105    delete result;
4106
4107    sLog.outString();
4108    sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() );
4109}
4110
4111void ObjectMgr::LoadInstanceTemplate()
4112{
4113    sInstanceTemplate.Load();
4114
4115    for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++)
4116    {
4117        InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i);
4118        if(!temp) continue;
4119        const MapEntry* entry = sMapStore.LookupEntry(temp->map);
4120        if(!entry)
4121        {
4122            sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map);
4123            continue;
4124        }
4125        else if(!entry->HasResetTime())
4126            continue;
4127
4128        if(temp->reset_delay == 0)
4129        {
4130            // use defaults from the DBC
4131            if(entry->SupportsHeroicMode())
4132            {
4133                temp->reset_delay = entry->resetTimeHeroic / DAY;
4134            }
4135            else if (entry->resetTimeRaid && entry->map_type == MAP_RAID)
4136            {
4137                temp->reset_delay = entry->resetTimeRaid / DAY;
4138            }
4139        }
4140
4141        // the reset_delay must be atleast one day
4142        temp->reset_delay = std::max((uint32)1, (uint32)(temp->reset_delay * sWorld.getRate(RATE_INSTANCE_RESET_TIME)));
4143    }
4144
4145    sLog.outString( ">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount );
4146    sLog.outString();
4147}
4148
4149void ObjectMgr::AddGossipText(GossipText *pGText)
4150{
4151    ASSERT( pGText->Text_ID );
4152    ASSERT( mGossipText.find(pGText->Text_ID) == mGossipText.end() );
4153    mGossipText[pGText->Text_ID] = pGText;
4154}
4155
4156GossipText *ObjectMgr::GetGossipText(uint32 Text_ID)
4157{
4158    GossipTextMap::const_iterator itr;
4159    for (itr = mGossipText.begin(); itr != mGossipText.end(); itr++)
4160    {
4161        if(itr->second->Text_ID == Text_ID)
4162            return itr->second;
4163    }
4164    return NULL;
4165}
4166
4167void ObjectMgr::LoadGossipText()
4168{
4169    GossipText *pGText;
4170    QueryResult *result = WorldDatabase.Query( "SELECT * FROM npc_text" );
4171
4172    int count = 0;
4173    if( !result )
4174    {
4175        barGoLink bar( 1 );
4176        bar.step();
4177
4178        sLog.outString();
4179        sLog.outString( ">> Loaded %u npc texts", count );
4180        return;
4181    }
4182
4183    int cic;
4184
4185    barGoLink bar( result->GetRowCount() );
4186
4187    do
4188    {
4189        ++count;
4190        cic = 0;
4191
4192        Field *fields = result->Fetch();
4193
4194        bar.step();
4195
4196        pGText = new GossipText;
4197        pGText->Text_ID    = fields[cic++].GetUInt32();
4198
4199        for (int i=0; i< 8; i++)
4200        {
4201            pGText->Options[i].Text_0           = fields[cic++].GetCppString();
4202            pGText->Options[i].Text_1           = fields[cic++].GetCppString();
4203
4204            pGText->Options[i].Language         = fields[cic++].GetUInt32();
4205            pGText->Options[i].Probability      = fields[cic++].GetFloat();
4206
4207            pGText->Options[i].Emotes[0]._Delay  = fields[cic++].GetUInt32();
4208            pGText->Options[i].Emotes[0]._Emote  = fields[cic++].GetUInt32();
4209
4210            pGText->Options[i].Emotes[1]._Delay  = fields[cic++].GetUInt32();
4211            pGText->Options[i].Emotes[1]._Emote  = fields[cic++].GetUInt32();
4212
4213            pGText->Options[i].Emotes[2]._Delay  = fields[cic++].GetUInt32();
4214            pGText->Options[i].Emotes[2]._Emote  = fields[cic++].GetUInt32();
4215        }
4216
4217        if ( !pGText->Text_ID ) continue;
4218        AddGossipText( pGText );
4219
4220    } while( result->NextRow() );
4221
4222    sLog.outString();
4223    sLog.outString( ">> Loaded %u npc texts", count );
4224    delete result;
4225}
4226
4227void ObjectMgr::LoadNpcTextLocales()
4228{
4229    mNpcTextLocaleMap.clear();
4230   
4231    QueryResult *result = WorldDatabase.Query("SELECT entry,"
4232        "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,"
4233        "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,"
4234        "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,"
4235        "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,"
4236        "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,"
4237        "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,"
4238        "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, "
4239        "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 "
4240        " FROM locales_npc_text");
4241
4242    if(!result)
4243    {
4244        barGoLink bar(1);
4245
4246        bar.step();
4247
4248        sLog.outString("");
4249        sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty.");
4250        return;
4251    }
4252
4253    barGoLink bar(result->GetRowCount());
4254
4255    do
4256    {
4257        Field *fields = result->Fetch();
4258        bar.step();
4259
4260        uint32 entry = fields[0].GetUInt32();
4261
4262        NpcTextLocale& data = mNpcTextLocaleMap[entry];
4263
4264        for(int i=1; i<MAX_LOCALE; ++i)
4265        {
4266            for(int j=0; j<8; ++j)
4267            {
4268                std::string str0 = fields[1+8*2*(i-1)+2*j].GetCppString();
4269                if(!str0.empty())
4270                {
4271                    int idx = GetOrNewIndexForLocale(LocaleConstant(i));
4272                    if(idx >= 0)
4273                    {
4274                        if(data.Text_0[j].size() <= idx)
4275                            data.Text_0[j].resize(idx+1);
4276
4277                        data.Text_0[j][idx] = str0;
4278                    }
4279                }
4280                std::string str1 = fields[1+8*2*(i-1)+2*j+1].GetCppString();
4281                if(!str1.empty())
4282                {
4283                    int idx = GetOrNewIndexForLocale(LocaleConstant(i));
4284                    if(idx >= 0)
4285                    {
4286                        if(data.Text_1[j].size() <= idx)
4287                            data.Text_1[j].resize(idx+1);
4288
4289                        data.Text_1[j][idx] = str1;
4290                    }
4291                }
4292            }
4293        }
4294    } while (result->NextRow());
4295
4296    delete result;
4297
4298    sLog.outString();
4299    sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() );
4300}
4301
4302//not very fast function but it is called only once a day, or on starting-up
4303void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
4304{
4305    time_t basetime = time(NULL);
4306    sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec);
4307    //delete all old mails without item and without body immediately, if starting server
4308    if (!serverUp)
4309        CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" I64FMTD "' AND has_items = '0' AND itemTextId = 0", (uint64)basetime);
4310    //                                                     0  1           2      3        4          5         6           7   8       9
4311    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);
4312    if ( !result )
4313        return;                                             // any mails need to be returned or deleted
4314    Field *fields;
4315    //std::ostringstream delitems, delmails; //will be here for optimization
4316    //bool deletemail = false, deleteitem = false;
4317    //delitems << "DELETE FROM item_instance WHERE guid IN ( ";
4318    //delmails << "DELETE FROM mail WHERE id IN ( "
4319    do
4320    {
4321        fields = result->Fetch();
4322        Mail *m = new Mail;
4323        m->messageID = fields[0].GetUInt32();
4324        m->messageType = fields[1].GetUInt8();
4325        m->sender = fields[2].GetUInt32();
4326        m->receiver = fields[3].GetUInt32();
4327        m->itemTextId = fields[4].GetUInt32();
4328        bool has_items = fields[5].GetBool();
4329        m->expire_time = (time_t)fields[6].GetUInt64();
4330        m->deliver_time = 0;
4331        m->COD = fields[7].GetUInt32();
4332        m->checked = fields[8].GetUInt32();
4333        m->mailTemplateId = fields[9].GetInt16();
4334
4335        Player *pl = 0;
4336        if (serverUp)
4337            pl = GetPlayer((uint64)m->receiver);
4338        if (pl && pl->m_mailsLoaded)
4339        {                                                   //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail
4340            //his in mailbox and he has already listed his mails )
4341            delete m;
4342            continue;
4343        }
4344        //delete or return mail:
4345        if (has_items)
4346        {
4347            QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", m->messageID);
4348            if(resultItems)
4349            {
4350                do
4351                {
4352                    Field *fields2 = resultItems->Fetch();
4353
4354                    uint32 item_guid_low = fields2[0].GetUInt32();
4355                    uint32 item_template = fields2[1].GetUInt32();
4356
4357                    m->AddItem(item_guid_low, item_template);
4358                }
4359                while (resultItems->NextRow());
4360
4361                delete resultItems;
4362            }
4363            //if it is mail from AH, it shouldn't be returned, but deleted
4364            if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_AUCTION | MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED)))
4365            {
4366                // mail open and then not returned
4367                for(std::vector<MailItemInfo>::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
4368                    CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid);
4369            }
4370            else
4371            {
4372                //mail will be returned:
4373                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);
4374                delete m;
4375                continue;
4376            }
4377        }
4378
4379        if (m->itemTextId)
4380            CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId);
4381
4382        //deletemail = true;
4383        //delmails << m->messageID << ", ";
4384        CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID);
4385        delete m;
4386    } while (result->NextRow());
4387    delete result;
4388}
4389
4390void ObjectMgr::LoadQuestAreaTriggers()
4391{
4392    mQuestAreaTriggerMap.clear();                           // need for reload case
4393
4394    QueryResult *result = WorldDatabase.Query( "SELECT id,quest FROM areatrigger_involvedrelation" );
4395
4396    uint32 count = 0;
4397
4398    if( !result )
4399    {
4400        barGoLink bar( 1 );
4401        bar.step();
4402
4403        sLog.outString();
4404        sLog.outString( ">> Loaded %u quest trigger points", count );
4405        return;
4406    }
4407
4408    barGoLink bar( result->GetRowCount() );
4409
4410    do
4411    {
4412        ++count;
4413        bar.step();
4414
4415        Field *fields = result->Fetch();
4416
4417        uint32 trigger_ID = fields[0].GetUInt32();
4418        uint32 quest_ID   = fields[1].GetUInt32();
4419
4420        AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID);
4421        if(!atEntry)
4422        {
4423            sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",trigger_ID);
4424            continue;
4425        }
4426
4427        Quest const* quest = GetQuestTemplate(quest_ID);
4428
4429        if(!quest)
4430        {
4431            sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u",trigger_ID,quest_ID);
4432            continue;
4433        }
4434
4435        if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
4436        {
4437            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);
4438
4439            // this will prevent quest completing without objective
4440            const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
4441
4442            // continue; - quest modified to required obkective and trigger can be allowed.
4443        }
4444
4445        mQuestAreaTriggerMap[trigger_ID] = quest_ID;
4446
4447    } while( result->NextRow() );
4448
4449    delete result;
4450
4451    sLog.outString();
4452    sLog.outString( ">> Loaded %u quest trigger points", count );
4453}
4454
4455void ObjectMgr::LoadTavernAreaTriggers()
4456{
4457    mTavernAreaTriggerSet.clear();                          // need for reload case
4458
4459    QueryResult *result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern");
4460
4461    uint32 count = 0;
4462
4463    if( !result )
4464    {
4465        barGoLink bar( 1 );
4466        bar.step();
4467
4468        sLog.outString();
4469        sLog.outString( ">> Loaded %u tavern triggers", count );
4470        return;
4471    }
4472
4473    barGoLink bar( result->GetRowCount() );
4474
4475    do
4476    {
4477        ++count;
4478        bar.step();
4479
4480        Field *fields = result->Fetch();
4481
4482        uint32 Trigger_ID      = fields[0].GetUInt32();
4483
4484        AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
4485        if(!atEntry)
4486        {
4487            sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
4488            continue;
4489        }
4490
4491        mTavernAreaTriggerSet.insert(Trigger_ID);
4492    } while( result->NextRow() );
4493
4494    delete result;
4495
4496    sLog.outString();
4497    sLog.outString( ">> Loaded %u tavern triggers", count );
4498}
4499
4500void ObjectMgr::LoadAreaTriggerScripts()
4501{
4502    mAreaTriggerScripts.clear();                            // need for reload case
4503    QueryResult *result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts");
4504
4505    uint32 count = 0;
4506
4507    if( !result )
4508    {
4509        barGoLink bar( 1 );
4510        bar.step();
4511
4512        sLog.outString();
4513        sLog.outString( ">> Loaded %u areatrigger scripts", count );
4514        return;
4515    }
4516
4517    barGoLink bar( result->GetRowCount() );
4518
4519    do
4520    {
4521        ++count;
4522        bar.step();
4523
4524        Field *fields = result->Fetch();
4525
4526        uint32 Trigger_ID      = fields[0].GetUInt32();
4527        std::string scriptName = fields[1].GetCppString();
4528
4529        AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
4530        if(!atEntry)
4531        {
4532            sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
4533            continue;
4534        }
4535        mAreaTriggerScripts[Trigger_ID] = scriptName;
4536    } while( result->NextRow() );
4537
4538    delete result;
4539
4540    sLog.outString();
4541    sLog.outString( ">> Loaded %u areatrigger scripts", count );
4542}
4543uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
4544{
4545    bool found = false;
4546    float dist;
4547    uint32 id = 0;
4548
4549    for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
4550    {
4551        TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
4552        if(node && node->map_id == mapid)
4553        {
4554            float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z);
4555            if(found)
4556            {
4557                if(dist2 < dist)
4558                {
4559                    dist = dist2;
4560                    id = i;
4561                }
4562            }
4563            else
4564            {
4565                found = true;
4566                dist = dist2;
4567                id = i;
4568            }
4569        }
4570    }
4571
4572    return id;
4573}
4574
4575void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost)
4576{
4577    TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source);
4578    if(src_i==sTaxiPathSetBySource.end())
4579    {
4580        path = 0;
4581        cost = 0;
4582        return;
4583    }
4584
4585    TaxiPathSetForSource& pathSet = src_i->second;
4586
4587    TaxiPathSetForSource::iterator dest_i = pathSet.find(destination);
4588    if(dest_i==pathSet.end())
4589    {
4590        path = 0;
4591        cost = 0;
4592        return;
4593    }
4594
4595    cost = dest_i->second.price;
4596    path = dest_i->second.ID;
4597}
4598
4599uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
4600{
4601    uint16 mount_entry = 0;
4602    uint16 mount_id = 0;
4603
4604    TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id);
4605    if(node)
4606    {
4607        if (team == ALLIANCE)
4608        {
4609            mount_entry = node->alliance_mount_type;
4610            CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
4611            if(ci)
4612                mount_id = ci->DisplayID_A;
4613        }
4614        if (team == HORDE)
4615        {
4616            mount_entry = node->horde_mount_type;
4617            CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
4618            if(ci)
4619                mount_id = ci->DisplayID_H;
4620        }
4621    }
4622
4623    CreatureModelInfo const *minfo = GetCreatureModelInfo(mount_id);
4624    if(!minfo)
4625    {
4626        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. ",
4627            mount_entry,id,team,mount_id);
4628
4629        return false;
4630    }
4631    if(minfo->modelid_other_gender!=0)
4632        mount_id = urand(0,1) ? mount_id : minfo->modelid_other_gender;
4633
4634    return mount_id;
4635}
4636
4637void ObjectMgr::GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds)
4638{
4639    if(path >= sTaxiPathNodesByPath.size())
4640        return;
4641
4642    TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path];
4643
4644    pathnodes.Resize(nodeList.size());
4645    mapIds.resize(nodeList.size());
4646
4647    for(size_t i = 0; i < nodeList.size(); ++i)
4648    {
4649        pathnodes[ i ].x = nodeList[i].x;
4650        pathnodes[ i ].y = nodeList[i].y;
4651        pathnodes[ i ].z = nodeList[i].z;
4652
4653        mapIds[i] = nodeList[i].mapid;
4654    }
4655}
4656
4657void ObjectMgr::GetTransportPathNodes( uint32 path, TransportPath &pathnodes )
4658{
4659    if(path >= sTaxiPathNodesByPath.size())
4660        return;
4661
4662    TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path];
4663
4664    pathnodes.Resize(nodeList.size());
4665
4666    for(size_t i = 0; i < nodeList.size(); ++i)
4667    {
4668        pathnodes[ i ].mapid = nodeList[i].mapid;
4669        pathnodes[ i ].x = nodeList[i].x;
4670        pathnodes[ i ].y = nodeList[i].y;
4671        pathnodes[ i ].z = nodeList[i].z;
4672        pathnodes[ i ].actionFlag = nodeList[i].actionFlag;
4673        pathnodes[ i ].delay = nodeList[i].delay;
4674    }
4675}
4676
4677void ObjectMgr::LoadGraveyardZones()
4678{
4679    mGraveYardMap.clear();                                  // need for reload case
4680
4681    QueryResult *result = WorldDatabase.Query("SELECT id,ghost_zone,faction FROM game_graveyard_zone");
4682
4683    uint32 count = 0;
4684
4685    if( !result )
4686    {
4687        barGoLink bar( 1 );
4688        bar.step();
4689
4690        sLog.outString();
4691        sLog.outString( ">> Loaded %u graveyard-zone links", count );
4692        return;
4693    }
4694
4695    barGoLink bar( result->GetRowCount() );
4696
4697    do
4698    {
4699        ++count;
4700        bar.step();
4701
4702        Field *fields = result->Fetch();
4703
4704        uint32 safeLocId = fields[0].GetUInt32();
4705        uint32 zoneId = fields[1].GetUInt32();
4706        uint32 team   = fields[2].GetUInt32();
4707
4708        WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId);
4709        if(!entry)
4710        {
4711            sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",safeLocId);
4712            continue;
4713        }
4714
4715        AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId);
4716        if(!areaEntry)
4717        {
4718            sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing zone id (%u), skipped.",zoneId);
4719            continue;
4720        }
4721
4722        if(areaEntry->zone != 0)
4723        {
4724            sLog.outErrorDb("Table `game_graveyard_zone` has record subzone id (%u) instead of zone, skipped.",zoneId);
4725            continue;
4726        }
4727
4728        if(team!=0 && team!=HORDE && team!=ALLIANCE)
4729        {
4730            sLog.outErrorDb("Table `game_graveyard_zone` has record for non player faction (%u), skipped.",team);
4731            continue;
4732        }
4733
4734        if(entry->map_id != areaEntry->mapid && team != 0)
4735        {
4736            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);
4737            team = 0;
4738        }
4739
4740        if(!AddGraveYardLink(safeLocId,zoneId,team,false))
4741            sLog.outErrorDb("Table `game_graveyard_zone` has a duplicate record for Garveyard (ID: %u) and Zone (ID: %u), skipped.",safeLocId,zoneId);
4742    } while( result->NextRow() );
4743
4744    delete result;
4745
4746    sLog.outString();
4747    sLog.outString( ">> Loaded %u graveyard-zone links", count );
4748}
4749
4750WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team)
4751{
4752    // search for zone associated closest graveyard
4753    uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y);
4754
4755    // Simulate std. algorithm:
4756    //   found some graveyard associated to (ghost_zone,ghost_map)
4757    //
4758    //   if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map
4759    //     then check faction
4760    //   if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated
4761    //     then skip check faction
4762    GraveYardMap::const_iterator graveLow  = mGraveYardMap.lower_bound(zoneId);
4763    GraveYardMap::const_iterator graveUp   = mGraveYardMap.upper_bound(zoneId);
4764    if(graveLow==graveUp)
4765    {
4766        sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
4767        return NULL;
4768    }
4769
4770    bool foundNear = false;
4771    float distNear;
4772    WorldSafeLocsEntry const* entryNear = NULL;
4773    WorldSafeLocsEntry const* entryFar = NULL;
4774
4775    for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr)
4776    {
4777        GraveYardData const& data = itr->second;
4778
4779        WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId);
4780        if(!entry)
4781        {
4782            sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",data.safeLocId);
4783            continue;
4784        }
4785
4786        // remember first graveyard at another map and ignore other
4787        if(MapId != entry->map_id)
4788        {
4789            if(!entryFar)
4790                entryFar = entry;
4791            continue;
4792        }
4793
4794        // skip enemy faction graveyard at same map (normal area, city, or battleground)
4795        // team == 0 case can be at call from .neargrave
4796        if(data.team != 0 && team != 0 && data.team != team)
4797            continue;
4798
4799        // find now nearest graveyard at same map
4800        float dist2 = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y)+(entry->z - z)*(entry->z - z);
4801        if(foundNear)
4802        {
4803            if(dist2 < distNear)
4804            {
4805                distNear = dist2;
4806                entryNear = entry;
4807            }
4808        }
4809        else
4810        {
4811            foundNear = true;
4812            distNear = dist2;
4813            entryNear = entry;
4814        }
4815    }
4816
4817    if(entryNear)
4818        return entryNear;
4819
4820    return entryFar;
4821}
4822
4823GraveYardData const* ObjectMgr::FindGraveYardData(uint32 id, uint32 zoneId)
4824{
4825    GraveYardMap::const_iterator graveLow  = mGraveYardMap.lower_bound(zoneId);
4826    GraveYardMap::const_iterator graveUp   = mGraveYardMap.upper_bound(zoneId);
4827
4828    for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr)
4829    {
4830        if(itr->second.safeLocId==id)
4831            return &itr->second;
4832    }
4833
4834    return NULL;
4835}
4836
4837bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB)
4838{
4839    if(FindGraveYardData(id,zoneId))
4840        return false;
4841
4842    // add link to loaded data
4843    GraveYardData data;
4844    data.safeLocId = id;
4845    data.team = team;
4846
4847    mGraveYardMap.insert(GraveYardMap::value_type(zoneId,data));
4848
4849    // add link to DB
4850    if(inDB)
4851    {
4852        WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone ( id,ghost_zone,faction) "
4853            "VALUES ('%u', '%u','%u')",id,zoneId,team);
4854    }
4855
4856    return true;
4857}
4858
4859void ObjectMgr::RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB)
4860{
4861    GraveYardMap::iterator graveLow  = mGraveYardMap.lower_bound(zoneId);
4862    GraveYardMap::iterator graveUp   = mGraveYardMap.upper_bound(zoneId);
4863    if(graveLow==graveUp)
4864    {
4865        //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
4866        return;
4867    }
4868
4869    bool found = false;
4870
4871    GraveYardMap::iterator itr;
4872
4873    for(itr = graveLow; itr != graveUp; ++itr)
4874    {
4875        GraveYardData & data = itr->second;
4876
4877        // skip not matching safezone id
4878        if(data.safeLocId != id)
4879            continue;
4880
4881        // skip enemy faction graveyard at same map (normal area, city, or battleground)
4882        // team == 0 case can be at call from .neargrave
4883        if(data.team != 0 && team != 0 && data.team != team)
4884            continue;
4885
4886        found = true;
4887        break;
4888    }
4889
4890    // no match, return
4891    if(!found)
4892        return;
4893
4894    // remove from links
4895    mGraveYardMap.erase(itr);
4896
4897    // remove link from DB
4898    if(inDB)
4899    {
4900        WorldDatabase.PExecute("DELETE FROM game_graveyard_zone WHERE id = '%u' AND ghost_zone = '%u' AND faction = '%u'",id,zoneId,team);
4901    }
4902
4903    return;
4904}
4905
4906
4907void ObjectMgr::LoadAreaTriggerTeleports()
4908{
4909    mAreaTriggers.clear();                                  // need for reload case
4910
4911    uint32 count = 0;
4912
4913    //                                                0   1               2              3               4           5            6                    7                     8           9                  10                 11                 12
4914    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");
4915    if( !result )
4916    {
4917
4918        barGoLink bar( 1 );
4919
4920        bar.step();
4921
4922        sLog.outString();
4923        sLog.outString( ">> Loaded %u area trigger teleport definitions", count );
4924        return;
4925    }
4926
4927    barGoLink bar( result->GetRowCount() );
4928
4929    do
4930    {
4931        Field *fields = result->Fetch();
4932
4933        bar.step();
4934
4935        ++count;
4936
4937        uint32 Trigger_ID = fields[0].GetUInt32();
4938
4939        AreaTrigger at;
4940
4941        at.requiredLevel      = fields[1].GetUInt8();
4942        at.requiredItem       = fields[2].GetUInt32();
4943        at.requiredItem2      = fields[3].GetUInt32();
4944        at.heroicKey          = fields[4].GetUInt32();
4945        at.heroicKey2         = fields[5].GetUInt32();
4946        at.requiredQuest      = fields[6].GetUInt32();
4947        at.requiredFailedText = fields[7].GetCppString();
4948        at.target_mapId       = fields[8].GetUInt32();
4949        at.target_X           = fields[9].GetFloat();
4950        at.target_Y           = fields[10].GetFloat();
4951        at.target_Z           = fields[11].GetFloat();
4952        at.target_Orientation = fields[12].GetFloat();
4953
4954        AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
4955        if(!atEntry)
4956        {
4957            sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
4958            continue;
4959        }
4960
4961        if(at.requiredItem)
4962        {
4963            ItemPrototype const *pProto = GetItemPrototype(at.requiredItem);
4964            if(!pProto)
4965            {
4966                sLog.outError("Key item %u does not exist for trigger %u, removing key requirement.", at.requiredItem, Trigger_ID);
4967                at.requiredItem = 0;
4968            }
4969        }
4970        if(at.requiredItem2)
4971        {
4972            ItemPrototype const *pProto = GetItemPrototype(at.requiredItem2);
4973            if(!pProto)
4974            {
4975                sLog.outError("Second item %u not exist for trigger %u, remove key requirement.", at.requiredItem2, Trigger_ID);
4976                at.requiredItem2 = 0;
4977            }
4978        }
4979
4980        if(at.heroicKey)
4981        {
4982            ItemPrototype const *pProto = GetItemPrototype(at.heroicKey);
4983            if(!pProto)
4984            {
4985                sLog.outError("Heroic key item %u not exist for trigger %u, remove key requirement.", at.heroicKey, Trigger_ID);
4986                at.heroicKey = 0;
4987            }
4988        }
4989
4990        if(at.heroicKey2)
4991        {
4992            ItemPrototype const *pProto = GetItemPrototype(at.heroicKey2);
4993            if(!pProto)
4994            {
4995                sLog.outError("Heroic second key item %u not exist for trigger %u, remove key requirement.", at.heroicKey2, Trigger_ID);
4996                at.heroicKey2 = 0;
4997            }
4998        }
4999
5000        if(at.requiredQuest)
5001        {
5002            if(!mQuestTemplates[at.requiredQuest])
5003            {
5004                sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",at.requiredQuest,Trigger_ID);
5005                at.requiredQuest = 0;
5006            }
5007        }
5008
5009        MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId);
5010        if(!mapEntry)
5011        {
5012            sLog.outErrorDb("Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Trigger_ID,at.target_mapId);
5013            continue;
5014        }
5015
5016        if(at.target_X==0 && at.target_Y==0 && at.target_Z==0)
5017        {
5018            sLog.outErrorDb("Area trigger (ID:%u) target coordinates not provided.",Trigger_ID);
5019            continue;
5020        }
5021
5022        mAreaTriggers[Trigger_ID] = at;
5023
5024    } while( result->NextRow() );
5025
5026    delete result;
5027
5028    sLog.outString();
5029    sLog.outString( ">> Loaded %u area trigger teleport definitions", count );
5030}
5031
5032AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const
5033{
5034    const MapEntry *mapEntry = sMapStore.LookupEntry(Map);
5035    if(!mapEntry) return NULL;
5036    for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); itr++)
5037    {
5038        if(itr->second.target_mapId == mapEntry->parent_map)
5039        {
5040            AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first);
5041            if(atEntry && atEntry->mapid == Map)
5042                return &itr->second;
5043        }
5044    }
5045    return NULL;
5046}
5047
5048void ObjectMgr::SetHighestGuids()
5049{
5050    QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" );
5051    if( result )
5052    {
5053        m_hiCharGuid = (*result)[0].GetUInt32()+1;
5054
5055        delete result;
5056    }
5057
5058    result = WorldDatabase.Query( "SELECT MAX(guid) FROM creature" );
5059    if( result )
5060    {
5061        m_hiCreatureGuid = (*result)[0].GetUInt32()+1;
5062
5063        delete result;
5064    }
5065
5066    result = CharacterDatabase.Query( "SELECT MAX(id) FROM character_pet" );
5067    if( result )
5068    {
5069        m_hiPetGuid = (*result)[0].GetUInt32()+1;
5070
5071        delete result;
5072    }
5073
5074    result = CharacterDatabase.Query( "SELECT MAX(guid) FROM item_instance" );
5075    if( result )
5076    {
5077        m_hiItemGuid = (*result)[0].GetUInt32()+1;
5078
5079        delete result;
5080    }
5081
5082    // Cleanup other tables from not existed guids (>=m_hiItemGuid)
5083    CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", m_hiItemGuid);
5084    CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_hiItemGuid);
5085    CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", m_hiItemGuid);
5086    CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_hiItemGuid);
5087
5088    result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" );
5089    if( result )
5090    {
5091        m_hiGoGuid = (*result)[0].GetUInt32()+1;
5092
5093        delete result;
5094    }
5095
5096    result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse" );
5097    if( result )
5098    {
5099        m_auctionid = (*result)[0].GetUInt32()+1;
5100
5101        delete result;
5102    }
5103    else
5104    {
5105        m_auctionid = 0;
5106    }
5107    result = CharacterDatabase.Query( "SELECT MAX(id) FROM mail" );
5108    if( result )
5109    {
5110        m_mailid = (*result)[0].GetUInt32()+1;
5111
5112        delete result;
5113    }
5114    else
5115    {
5116        m_mailid = 0;
5117    }
5118    result = CharacterDatabase.Query( "SELECT MAX(id) FROM item_text" );
5119    if( result )
5120    {
5121        m_ItemTextId = (*result)[0].GetUInt32();
5122
5123        delete result;
5124    }
5125    else
5126        m_ItemTextId = 0;
5127
5128    result = CharacterDatabase.Query( "SELECT MAX(guid) FROM corpse" );
5129    if( result )
5130    {
5131        m_hiCorpseGuid = (*result)[0].GetUInt32()+1;
5132
5133        delete result;
5134    }
5135}
5136
5137uint32 ObjectMgr::GenerateAuctionID()
5138{
5139    ++m_auctionid;
5140    if(m_auctionid>=0xFFFFFFFF)
5141    {
5142        sLog.outError("Auctions ids overflow!! Can't continue, shuting down server. ");
5143        sWorld.m_stopEvent = true;
5144    }
5145    return m_auctionid;
5146}
5147
5148uint32 ObjectMgr::GenerateMailID()
5149{
5150    ++m_mailid;
5151    if(m_mailid>=0xFFFFFFFF)
5152    {
5153        sLog.outError("Mail ids overflow!! Can't continue, shuting down server. ");
5154        sWorld.m_stopEvent = true;
5155    }
5156    return m_mailid;
5157}
5158
5159uint32 ObjectMgr::GenerateItemTextID()
5160{
5161    ++m_ItemTextId;
5162    if(m_ItemTextId>=0xFFFFFFFF)
5163    {
5164        sLog.outError("Item text ids overflow!! Can't continue, shuting down server. ");
5165        sWorld.m_stopEvent = true;
5166    }
5167    return m_ItemTextId;
5168}
5169
5170uint32 ObjectMgr::CreateItemText(std::string text)
5171{
5172    uint32 newItemTextId = GenerateItemTextID();
5173    //insert new itempage to container
5174    mItemTexts[ newItemTextId ] = text;
5175    //save new itempage
5176    CharacterDatabase.escape_string(text);
5177    //any Delete query needed, itemTextId is maximum of all ids
5178    std::ostringstream query;
5179    query << "INSERT INTO item_text (id,text) VALUES ( '" << newItemTextId << "', '" << text << "')";
5180    CharacterDatabase.Execute(query.str().c_str());         //needs to be run this way, because mail body may be more than 1024 characters
5181    return newItemTextId;
5182}
5183
5184uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh)
5185{
5186    switch(guidhigh)
5187    {
5188        case HIGHGUID_ITEM:
5189            ++m_hiItemGuid;
5190            if(m_hiItemGuid>=0xFFFFFFFF)
5191            {
5192                sLog.outError("Item guid overflow!! Can't continue, shuting down server. ");
5193                sWorld.m_stopEvent = true;
5194            }
5195            return m_hiItemGuid;
5196        case HIGHGUID_UNIT:
5197            ++m_hiCreatureGuid;
5198            if(m_hiCreatureGuid>=0x00FFFFFF)
5199            {
5200                sLog.outError("Creature guid overflow!! Can't continue, shuting down server. ");
5201                sWorld.m_stopEvent = true;
5202            }
5203            return m_hiCreatureGuid;
5204        case HIGHGUID_PET:
5205            ++m_hiPetGuid;
5206            if(m_hiPetGuid>=0x00FFFFFF)
5207            {
5208                sLog.outError("Pet guid overflow!! Can't continue, shuting down server. ");
5209                sWorld.m_stopEvent = true;
5210            }
5211            return m_hiPetGuid;
5212        case HIGHGUID_PLAYER:
5213            ++m_hiCharGuid;
5214            if(m_hiCharGuid>=0xFFFFFFFF)
5215            {
5216                sLog.outError("Players guid overflow!! Can't continue, shuting down server. ");
5217                sWorld.m_stopEvent = true;
5218            }
5219            return m_hiCharGuid;
5220        case HIGHGUID_GAMEOBJECT:
5221            ++m_hiGoGuid;
5222            if(m_hiGoGuid>=0x00FFFFFF)
5223            {
5224                sLog.outError("Gameobject guid overflow!! Can't continue, shuting down server. ");
5225                sWorld.m_stopEvent = true;
5226            }
5227            return m_hiGoGuid;
5228        case HIGHGUID_CORPSE:
5229            ++m_hiCorpseGuid;
5230            if(m_hiCorpseGuid>=0xFFFFFFFF)
5231            {
5232                sLog.outError("Corpse guid overflow!! Can't continue, shuting down server. ");
5233                sWorld.m_stopEvent = true;
5234            }
5235            return m_hiCorpseGuid;
5236        case HIGHGUID_DYNAMICOBJECT:
5237            ++m_hiDoGuid;
5238            if(m_hiDoGuid>=0xFFFFFFFF)
5239            {
5240                sLog.outError("DynamicObject guid overflow!! Can't continue, shuting down server. ");
5241                sWorld.m_stopEvent = true;
5242            }
5243            return m_hiDoGuid;
5244        default:
5245            ASSERT(0);
5246    }
5247
5248    ASSERT(0);
5249    return 0;
5250}
5251
5252void ObjectMgr::LoadGameObjectLocales()
5253{
5254    mGameObjectLocaleMap.clear();
5255   
5256    QueryResult *result = WorldDatabase.Query("SELECT entry,"
5257        "name_loc1,name_loc2,name_loc3,name_loc4,name_loc5,name_loc6,name_loc7,name_loc8,"
5258        "castbarcaption_loc1,castbarcaption_loc2,castbarcaption_loc3,castbarcaption_loc4,"
5259        "castbarcaption_loc5,castbarcaption_loc6,castbarcaption_loc7,castbarcaption_loc8 FROM locales_gameobject");
5260
5261    if(!result)
5262    {
5263        barGoLink bar(1);
5264
5265        bar.step();
5266
5267        sLog.outString("");
5268        sLog.outString(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty.");
5269        return;
5270    }
5271
5272    barGoLink bar(result->GetRowCount());
5273
5274    do
5275    {
5276        Field *fields = result->Fetch();
5277        bar.step();
5278
5279        uint32 entry = fields[0].GetUInt32();
5280
5281        GameObjectLocale& data = mGameObjectLocaleMap[entry];
5282
5283        for(int i = 1; i < MAX_LOCALE; ++i)
5284        {
5285            std::string str = fields[i].GetCppString();
5286            if(!str.empty())
5287            {
5288                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
5289                if(idx >= 0)
5290                {
5291                    if(data.Name.size() <= idx)
5292                        data.Name.resize(idx+1);
5293
5294                    data.Name[idx] = str;
5295                }
5296            }
5297        }
5298
5299        for(int i = MAX_LOCALE; i < MAX_LOCALE*2-1; ++i)
5300        {
5301            std::string str = fields[i].GetCppString();
5302            if(!str.empty())
5303            {
5304                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
5305                if(idx >= 0)
5306                {
5307                    if(data.CastBarCaption.size() <= idx)
5308                        data.CastBarCaption.resize(idx+1);
5309
5310                    data.CastBarCaption[idx] = str;
5311                }
5312            }
5313        }
5314
5315    } while (result->NextRow());
5316
5317    delete result;
5318
5319    sLog.outString();
5320    sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() );
5321}
5322
5323void ObjectMgr::LoadGameobjectInfo()
5324{
5325    sGOStorage.Load();
5326
5327    // some checks
5328    for(uint32 id = 1; id < sGOStorage.MaxEntry; id++)
5329    {
5330        GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(id);
5331        if(!goInfo)
5332            continue;
5333
5334        switch(goInfo->type)
5335        {
5336            case GAMEOBJECT_TYPE_DOOR:                      //0
5337            {
5338                if(goInfo->door.lockId)
5339                {
5340                    if(!sLockStore.LookupEntry(goInfo->door.lockId))
5341                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
5342                            id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId);
5343                }
5344                break;
5345            }
5346            case GAMEOBJECT_TYPE_BUTTON:                    //1
5347            {
5348                if(goInfo->button.lockId)
5349                {
5350                    if(!sLockStore.LookupEntry(goInfo->button.lockId))
5351                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
5352                            id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId);
5353                }
5354                break;
5355            }
5356            case GAMEOBJECT_TYPE_CHEST:                     //3
5357            {
5358                if(goInfo->chest.lockId)
5359                {
5360                    if(!sLockStore.LookupEntry(goInfo->chest.lockId))
5361                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.",
5362                            id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId);
5363                }
5364                if(goInfo->chest.linkedTrapId)              // linked trap
5365                {
5366                    if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->chest.linkedTrapId))
5367                    {
5368                        if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
5369                            sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
5370                                id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
5371                    }
5372                    /* disable check for while
5373                    else
5374                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
5375                            id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId);
5376                    */
5377                }
5378                break;
5379            }
5380            case GAMEOBJECT_TYPE_TRAP:                      //6
5381            {
5382                /* disable check for while
5383                if(goInfo->trap.spellId)                    // spell
5384                {
5385                    if(!sSpellStore.LookupEntry(goInfo->trap.spellId))
5386                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
5387                            id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId);
5388                }
5389                */
5390                break;
5391            }
5392            case GAMEOBJECT_TYPE_CHAIR:                     //7
5393                if(goInfo->chair.height > 2)
5394                {
5395                    sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..2.",
5396                        id,goInfo->type,goInfo->chair.height);
5397
5398                    // prevent client and server unexpected work
5399                    const_cast<GameObjectInfo*>(goInfo)->chair.height = 0;
5400                }
5401                break;
5402            case GAMEOBJECT_TYPE_SPELL_FOCUS:               //8
5403            {
5404                if(goInfo->spellFocus.focusId)
5405                {
5406                    if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId))
5407                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.",
5408                            id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId);
5409                }
5410
5411                if(goInfo->spellFocus.linkedTrapId)         // linked trap
5412                {
5413                    if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->spellFocus.linkedTrapId))
5414                    {
5415                        if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
5416                            sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
5417                                id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
5418                    }
5419                    /* disable check for while
5420                    else
5421                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
5422                            id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId);
5423                    */
5424                }
5425                break;
5426            }
5427            case GAMEOBJECT_TYPE_GOOBER:                    //10
5428            {
5429                if(goInfo->goober.pageId)                   // pageId
5430                {
5431                    if(!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
5432                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.",
5433                            id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId);
5434                }
5435                /* disable check for while
5436                if(goInfo->goober.spellId)                  // spell
5437                {
5438                    if(!sSpellStore.LookupEntry(goInfo->goober.spellId))
5439                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.",
5440                            id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId);
5441                }
5442                */
5443                if(goInfo->goober.linkedTrapId)             // linked trap
5444                {
5445                    if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->goober.linkedTrapId))
5446                    {
5447                        if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
5448                            sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
5449                                id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
5450                    }
5451                    /* disable check for while
5452                    else
5453                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
5454                            id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId);
5455                    */
5456                }
5457                break;
5458            }
5459            case GAMEOBJECT_TYPE_MO_TRANSPORT:              //15
5460            {
5461                if(goInfo->moTransport.taxiPathId)
5462                {
5463                    if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty())
5464                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
5465                            id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId);
5466                }
5467                break;
5468            }
5469            case GAMEOBJECT_TYPE_SUMMONING_RITUAL:          //18
5470            {
5471                /* disabled
5472                if(goInfo->summoningRitual.spellId)
5473                {
5474                    if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId))
5475                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.",
5476                            id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId);
5477                }
5478                */
5479                break;
5480            }
5481            case GAMEOBJECT_TYPE_SPELLCASTER:               //22
5482            {
5483                if(goInfo->spellcaster.spellId)             // spell
5484                {
5485                    if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId))
5486                        sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
5487                            id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId);
5488                }
5489                break;
5490            }
5491        }
5492    }
5493
5494    sLog.outString( ">> Loaded %u game object templates", sGOStorage.RecordCount );
5495    sLog.outString();
5496}
5497
5498void ObjectMgr::LoadExplorationBaseXP()
5499{
5500    uint32 count = 0;
5501    QueryResult *result = WorldDatabase.Query("SELECT level,basexp FROM exploration_basexp");
5502
5503    if( !result )
5504    {
5505        barGoLink bar( 1 );
5506
5507        bar.step();
5508
5509        sLog.outString();
5510        sLog.outString( ">> Loaded %u BaseXP definitions", count );
5511        return;
5512    }
5513
5514    barGoLink bar( result->GetRowCount() );
5515
5516    do
5517    {
5518        bar.step();
5519
5520        Field *fields = result->Fetch();
5521        uint32 level  = fields[0].GetUInt32();
5522        uint32 basexp = fields[1].GetUInt32();
5523        mBaseXPTable[level] = basexp;
5524        ++count;
5525    }
5526    while (result->NextRow());
5527
5528    delete result;
5529
5530    sLog.outString();
5531    sLog.outString( ">> Loaded %u BaseXP definitions", count );
5532}
5533
5534uint32 ObjectMgr::GetBaseXP(uint32 level)
5535{
5536    return mBaseXPTable[level] ? mBaseXPTable[level] : 0;
5537}
5538
5539void ObjectMgr::LoadPetNames()
5540{
5541    uint32 count = 0;
5542    QueryResult *result = WorldDatabase.Query("SELECT word,entry,half FROM pet_name_generation");
5543
5544    if( !result )
5545    {
5546        barGoLink bar( 1 );
5547
5548        bar.step();
5549
5550        sLog.outString();
5551        sLog.outString( ">> Loaded %u pet name parts", count );
5552        return;
5553    }
5554
5555    barGoLink bar( result->GetRowCount() );
5556
5557    do
5558    {
5559        bar.step();
5560
5561        Field *fields = result->Fetch();
5562        std::string word = fields[0].GetString();
5563        uint32 entry     = fields[1].GetUInt32();
5564        bool   half      = fields[2].GetBool();
5565        if(half)
5566            PetHalfName1[entry].push_back(word);
5567        else
5568            PetHalfName0[entry].push_back(word);
5569        ++count;
5570    }
5571    while (result->NextRow());
5572    delete result;
5573
5574    sLog.outString();
5575    sLog.outString( ">> Loaded %u pet name parts", count );
5576}
5577
5578void ObjectMgr::LoadPetNumber()
5579{
5580    QueryResult* result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet");
5581    if(result)
5582    {
5583        Field *fields = result->Fetch();
5584        m_hiPetNumber = fields[0].GetUInt32()+1;
5585        delete result;
5586    }
5587
5588    barGoLink bar( 1 );
5589    bar.step();
5590
5591    sLog.outString();
5592    sLog.outString( ">> Loaded the max pet number: %d", m_hiPetNumber-1);
5593}
5594
5595std::string ObjectMgr::GeneratePetName(uint32 entry)
5596{
5597    std::vector<std::string> & list0 = PetHalfName0[entry];
5598    std::vector<std::string> & list1 = PetHalfName1[entry];
5599
5600    if(list0.empty() || list1.empty())
5601    {
5602        CreatureInfo const *cinfo = GetCreatureTemplate(entry);
5603        char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale());
5604        if(!petname)
5605            petname = cinfo->Name;
5606        return std::string(petname);
5607    }
5608
5609    return *(list0.begin()+urand(0, list0.size()-1)) + *(list1.begin()+urand(0, list1.size()-1));
5610}
5611
5612uint32 ObjectMgr::GeneratePetNumber()
5613{
5614    return ++m_hiPetNumber;
5615}
5616
5617void ObjectMgr::LoadCorpses()
5618{
5619    uint32 count = 0;
5620    //                                                     0           1           2           3            4    5     6     7            8         10
5621    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");
5622
5623    if( !result )
5624    {
5625        barGoLink bar( 1 );
5626
5627        bar.step();
5628
5629        sLog.outString();
5630        sLog.outString( ">> Loaded %u corpses", count );
5631        return;
5632    }
5633
5634    barGoLink bar( result->GetRowCount() );
5635
5636    do
5637    {
5638        bar.step();
5639
5640        Field *fields = result->Fetch();
5641
5642        uint32 guid = fields[result->GetFieldCount()-1].GetUInt32();
5643
5644        Corpse *corpse = new Corpse;
5645        if(!corpse->LoadFromDB(guid,fields))
5646        {
5647            delete corpse;
5648            continue;
5649        }
5650
5651        ObjectAccessor::Instance().AddCorpse(corpse);
5652
5653        ++count;
5654    }
5655    while (result->NextRow());
5656    delete result;
5657
5658    sLog.outString();
5659    sLog.outString( ">> Loaded %u corpses", count );
5660}
5661
5662void ObjectMgr::LoadReputationOnKill()
5663{
5664    uint32 count = 0;
5665
5666    //                                                0            1                     2
5667    QueryResult *result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2,"
5668    //   3             4             5                   6             7             8                   9
5669        "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent "
5670        "FROM creature_onkill_reputation");
5671
5672    if(!result)
5673    {
5674        barGoLink bar(1);
5675
5676        bar.step();
5677
5678        sLog.outString();
5679        sLog.outErrorDb(">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty.");
5680        return;
5681    }
5682
5683    barGoLink bar(result->GetRowCount());
5684
5685    do
5686    {
5687        Field *fields = result->Fetch();
5688        bar.step();
5689
5690        uint32 creature_id = fields[0].GetUInt32();
5691
5692        ReputationOnKillEntry repOnKill;
5693        repOnKill.repfaction1          = fields[1].GetUInt32();
5694        repOnKill.repfaction2          = fields[2].GetUInt32();
5695        repOnKill.is_teamaward1        = fields[3].GetBool();
5696        repOnKill.reputation_max_cap1  = fields[4].GetUInt32();
5697        repOnKill.repvalue1            = fields[5].GetInt32();
5698        repOnKill.is_teamaward2        = fields[6].GetBool();
5699        repOnKill.reputation_max_cap2  = fields[7].GetUInt32();
5700        repOnKill.repvalue2            = fields[8].GetInt32();
5701        repOnKill.team_dependent       = fields[9].GetUInt8();
5702
5703        if(!GetCreatureTemplate(creature_id))
5704        {
5705            sLog.outErrorDb("Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped",creature_id);
5706            continue;
5707        }
5708
5709        if(repOnKill.repfaction1)
5710        {
5711            FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repOnKill.repfaction1);
5712            if(!factionEntry1)
5713            {
5714                sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction1);
5715                continue;
5716            }
5717        }
5718
5719        if(repOnKill.repfaction2)
5720        {
5721            FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repOnKill.repfaction2);
5722            if(!factionEntry2)
5723            {
5724                sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction2);
5725                continue;
5726            }
5727        }
5728
5729        mRepOnKill[creature_id] = repOnKill;
5730
5731        ++count;
5732    } while (result->NextRow());
5733
5734    delete result;
5735
5736    sLog.outString();
5737    sLog.outString(">> Loaded %u creature award reputation definitions", count);
5738}
5739
5740void ObjectMgr::LoadWeatherZoneChances()
5741{
5742    uint32 count = 0;
5743
5744    //                                                0     1                   2                   3                    4                   5                   6                    7                 8                 9                  10                  11                  12
5745    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");
5746
5747    if(!result)
5748    {
5749        barGoLink bar(1);
5750
5751        bar.step();
5752
5753        sLog.outString();
5754        sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty.");
5755        return;
5756    }
5757
5758    barGoLink bar(result->GetRowCount());
5759
5760    do
5761    {
5762        Field *fields = result->Fetch();
5763        bar.step();
5764
5765        uint32 zone_id = fields[0].GetUInt32();
5766
5767        WeatherZoneChances& wzc = mWeatherZoneMap[zone_id];
5768
5769        for(int season = 0; season < WEATHER_SEASONS; ++season)
5770        {
5771            wzc.data[season].rainChance  = fields[season * (MAX_WEATHER_TYPE-1) + 1].GetUInt32();
5772            wzc.data[season].snowChance  = fields[season * (MAX_WEATHER_TYPE-1) + 2].GetUInt32();
5773            wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE-1) + 3].GetUInt32();
5774
5775            if(wzc.data[season].rainChance > 100)
5776            {
5777                wzc.data[season].rainChance = 25;
5778                sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%",zone_id,season);
5779            }
5780
5781            if(wzc.data[season].snowChance > 100)
5782            {
5783                wzc.data[season].snowChance = 25;
5784                sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%",zone_id,season);
5785            }
5786
5787            if(wzc.data[season].stormChance > 100)
5788            {
5789                wzc.data[season].stormChance = 25;
5790                sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%",zone_id,season);
5791            }
5792        }
5793
5794        ++count;
5795    } while (result->NextRow());
5796
5797    delete result;
5798
5799    sLog.outString();
5800    sLog.outString(">> Loaded %u weather definitions", count);
5801}
5802
5803void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t)
5804{
5805    mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t;
5806    WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance);
5807    if(t)
5808        WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance);
5809}
5810
5811void ObjectMgr::DeleteCreatureData(uint32 guid)
5812{
5813    // remove mapid*cellid -> guid_set map
5814    CreatureData const* data = GetCreatureData(guid);
5815    if(data)
5816        RemoveCreatureFromGrid(guid, data);
5817
5818    mCreatureDataMap.erase(guid);
5819}
5820
5821void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t)
5822{
5823    mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t;
5824    WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance);
5825    if(t)
5826        WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance);
5827}
5828
5829void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance)
5830{
5831    RespawnTimes::iterator next;
5832
5833    for(RespawnTimes::iterator itr = mGORespawnTimes.begin(); itr != mGORespawnTimes.end(); itr = next)
5834    {
5835        next = itr;
5836        ++next;
5837
5838        if(GUID_HIPART(itr->first)==instance)
5839            mGORespawnTimes.erase(itr);
5840    }
5841
5842    for(RespawnTimes::iterator itr = mCreatureRespawnTimes.begin(); itr != mCreatureRespawnTimes.end(); itr = next)
5843    {
5844        next = itr;
5845        ++next;
5846
5847        if(GUID_HIPART(itr->first)==instance)
5848            mCreatureRespawnTimes.erase(itr);
5849    }
5850
5851    WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", instance);
5852    WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", instance);
5853}
5854
5855void ObjectMgr::DeleteGOData(uint32 guid)
5856{
5857    // remove mapid*cellid -> guid_set map
5858    GameObjectData const* data = GetGOData(guid);
5859    if(data)
5860        RemoveGameobjectFromGrid(guid, data);
5861
5862    mGameObjectDataMap.erase(guid);
5863}
5864
5865void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance)
5866{
5867    // corpses are always added to spawn mode 0 and they are spawned by their instance id
5868    CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid];
5869    cell_guids.corpses[player_guid] = instance;
5870}
5871
5872void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid)
5873{
5874    // corpses are always added to spawn mode 0 and they are spawned by their instance id
5875    CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid];
5876    cell_guids.corpses.erase(player_guid);
5877}
5878
5879void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map,char const* table)
5880{
5881    map.clear();                                            // need for reload case
5882
5883    uint32 count = 0;
5884
5885    QueryResult *result = WorldDatabase.PQuery("SELECT id,quest FROM %s",table);
5886
5887    if(!result)
5888    {
5889        barGoLink bar(1);
5890
5891        bar.step();
5892
5893        sLog.outString();
5894        sLog.outErrorDb(">> Loaded 0 quest relations from %s. DB table `%s` is empty.",table,table);
5895        return;
5896    }
5897
5898    barGoLink bar(result->GetRowCount());
5899
5900    do
5901    {
5902        Field *fields = result->Fetch();
5903        bar.step();
5904
5905        uint32 id    = fields[0].GetUInt32();
5906        uint32 quest = fields[1].GetUInt32();
5907
5908        if(mQuestTemplates.find(quest) == mQuestTemplates.end())
5909        {
5910            sLog.outErrorDb("Table `%s: Quest %u listed for entry %u does not exist.",table,quest,id);
5911            continue;
5912        }
5913
5914        map.insert(QuestRelations::value_type(id,quest));
5915
5916        ++count;
5917    } while (result->NextRow());
5918
5919    delete result;
5920
5921    sLog.outString();
5922    sLog.outString(">> Loaded %u quest relations from %s", count,table);
5923}
5924
5925void ObjectMgr::LoadGameobjectQuestRelations()
5926{
5927    LoadQuestRelationsHelper(mGOQuestRelations,"gameobject_questrelation");
5928
5929    for(QuestRelations::iterator itr = mGOQuestRelations.begin(); itr != mGOQuestRelations.end(); ++itr)
5930    {
5931        GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first);
5932        if(!goInfo)
5933            sLog.outErrorDb("Table `gameobject_questrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second);
5934        else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
5935            sLog.outErrorDb("Table `gameobject_questrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second);
5936    }
5937}
5938
5939void ObjectMgr::LoadGameobjectInvolvedRelations()
5940{
5941    LoadQuestRelationsHelper(mGOQuestInvolvedRelations,"gameobject_involvedrelation");
5942
5943    for(QuestRelations::iterator itr = mGOQuestInvolvedRelations.begin(); itr != mGOQuestInvolvedRelations.end(); ++itr)
5944    {
5945        GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first);
5946        if(!goInfo)
5947            sLog.outErrorDb("Table `gameobject_involvedrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second);
5948        else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
5949            sLog.outErrorDb("Table `gameobject_involvedrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second);
5950    }
5951}
5952
5953void ObjectMgr::LoadCreatureQuestRelations()
5954{
5955    LoadQuestRelationsHelper(mCreatureQuestRelations,"creature_questrelation");
5956
5957    for(QuestRelations::iterator itr = mCreatureQuestRelations.begin(); itr != mCreatureQuestRelations.end(); ++itr)
5958    {
5959        CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
5960        if(!cInfo)
5961            sLog.outErrorDb("Table `creature_questrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second);
5962        else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
5963            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);
5964    }
5965}
5966
5967void ObjectMgr::LoadCreatureInvolvedRelations()
5968{
5969    LoadQuestRelationsHelper(mCreatureQuestInvolvedRelations,"creature_involvedrelation");
5970
5971    for(QuestRelations::iterator itr = mCreatureQuestInvolvedRelations.begin(); itr != mCreatureQuestInvolvedRelations.end(); ++itr)
5972    {
5973        CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
5974        if(!cInfo)
5975            sLog.outErrorDb("Table `creature_involvedrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second);
5976        else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
5977            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);
5978    }
5979}
5980
5981void ObjectMgr::LoadReservedPlayersNames()
5982{
5983    m_ReservedNames.clear();                                // need for reload case
5984
5985    QueryResult *result = WorldDatabase.PQuery("SELECT name FROM reserved_name");
5986
5987    uint32 count = 0;
5988
5989    if( !result )
5990    {
5991        barGoLink bar( 1 );
5992        bar.step();
5993
5994        sLog.outString();
5995        sLog.outString( ">> Loaded %u reserved player names", count );
5996        return;
5997    }
5998
5999    barGoLink bar( result->GetRowCount() );
6000
6001    Field* fields;
6002    do
6003    {
6004        bar.step();
6005        fields = result->Fetch();
6006        std::string name= fields[0].GetCppString();
6007        if(normalizePlayerName(name))
6008        {
6009            m_ReservedNames.insert(name);
6010            ++count;
6011        }
6012    } while ( result->NextRow() );
6013
6014    delete result;
6015
6016    sLog.outString();
6017    sLog.outString( ">> Loaded %u reserved player names", count );
6018}
6019
6020enum LanguageType
6021{
6022    LT_BASIC_LATIN    = 0x0000,
6023    LT_EXTENDEN_LATIN = 0x0001,
6024    LT_CYRILLIC       = 0x0002,
6025    LT_EAST_ASIA      = 0x0004,
6026    LT_ANY            = 0xFFFF
6027};
6028
6029static LanguageType GetRealmLanguageType(bool create)
6030{
6031    switch(sWorld.getConfig(CONFIG_REALM_ZONE))
6032    {
6033        case REALM_ZONE_UNKNOWN:                            // any language
6034        case REALM_ZONE_DEVELOPMENT:
6035        case REALM_ZONE_TEST_SERVER:
6036        case REALM_ZONE_QA_SERVER:
6037            return LT_ANY;
6038        case REALM_ZONE_UNITED_STATES:                      // extended-Latin
6039        case REALM_ZONE_OCEANIC:
6040        case REALM_ZONE_LATIN_AMERICA:
6041        case REALM_ZONE_ENGLISH:
6042        case REALM_ZONE_GERMAN:
6043        case REALM_ZONE_FRENCH:
6044        case REALM_ZONE_SPANISH:
6045            return LT_EXTENDEN_LATIN;
6046        case REALM_ZONE_KOREA:                              // East-Asian
6047        case REALM_ZONE_TAIWAN:
6048        case REALM_ZONE_CHINA:
6049            return LT_EAST_ASIA;
6050        case REALM_ZONE_RUSSIAN:                            // Cyrillic
6051            return LT_CYRILLIC;
6052        default:
6053            return create ? LT_BASIC_LATIN : LT_ANY;        // basic-Latin at create, any at login
6054    }
6055}
6056
6057bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bool create = false)
6058{
6059    if(strictMask==0)                                       // any language, ignore realm
6060    {
6061        if(isExtendedLatinString(wstr,numericOrSpace))
6062            return true;
6063        if(isCyrillicString(wstr,numericOrSpace))
6064            return true;
6065        if(isEastAsianString(wstr,numericOrSpace))
6066            return true;
6067        return false;
6068    }
6069
6070    if(strictMask & 0x2)                                    // realm zone specific
6071    {
6072        LanguageType lt = GetRealmLanguageType(create);
6073        if(lt & LT_EXTENDEN_LATIN)
6074            if(isExtendedLatinString(wstr,numericOrSpace))
6075                return true;
6076        if(lt & LT_CYRILLIC)
6077            if(isCyrillicString(wstr,numericOrSpace))
6078                return true;
6079        if(lt & LT_EAST_ASIA)
6080            if(isEastAsianString(wstr,numericOrSpace))
6081                return true;
6082    }
6083
6084    if(strictMask & 0x1)                                    // basic latin
6085    {
6086        if(isBasicLatinString(wstr,numericOrSpace))
6087            return true;
6088    }
6089
6090    return false;
6091}
6092
6093bool ObjectMgr::IsValidName( std::string name, bool create )
6094{
6095    std::wstring wname;
6096    if(!Utf8toWStr(name,wname))
6097        return false;
6098
6099    if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME)
6100        return false;
6101
6102    uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES);
6103
6104    return isValidString(wname,strictMask,false,create);
6105}
6106
6107bool ObjectMgr::IsValidCharterName( std::string name )
6108{
6109    std::wstring wname;
6110    if(!Utf8toWStr(name,wname))
6111        return false;
6112
6113    if(wname.size() < 1)
6114        return false;
6115
6116    uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES);
6117
6118    return isValidString(wname,strictMask,true);
6119}
6120
6121bool ObjectMgr::IsValidPetName( std::string name )
6122{
6123    std::wstring wname;
6124    if(!Utf8toWStr(name,wname))
6125        return false;
6126
6127    if(wname.size() < 1)
6128        return false;
6129
6130    uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES);
6131
6132    return isValidString(wname,strictMask,false);
6133}
6134
6135int ObjectMgr::GetIndexForLocale( LocaleConstant loc )
6136{
6137    if(loc==LOCALE_enUS)
6138        return -1;
6139
6140    for(size_t i=0;i < m_LocalForIndex.size(); ++i)
6141        if(m_LocalForIndex[i]==loc)
6142            return i;
6143
6144    return -1;
6145}
6146
6147LocaleConstant ObjectMgr::GetLocaleForIndex(int i)
6148{
6149    if (i<0 || i>=m_LocalForIndex.size())
6150        return LOCALE_enUS;
6151
6152    return m_LocalForIndex[i];
6153}
6154
6155int ObjectMgr::GetOrNewIndexForLocale( LocaleConstant loc )
6156{
6157    if(loc==LOCALE_enUS)
6158        return -1;
6159
6160    for(size_t i=0;i < m_LocalForIndex.size(); ++i)
6161        if(m_LocalForIndex[i]==loc)
6162            return i;
6163
6164    m_LocalForIndex.push_back(loc);
6165    return m_LocalForIndex.size()-1;
6166}
6167
6168void ObjectMgr::LoadBattleMastersEntry()
6169{
6170    mBattleMastersMap.clear();                              // need for reload case
6171
6172    QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
6173
6174    uint32 count = 0;
6175
6176    if( !result )
6177    {
6178        barGoLink bar( 1 );
6179        bar.step();
6180
6181        sLog.outString();
6182        sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
6183        return;
6184    }
6185
6186    barGoLink bar( result->GetRowCount() );
6187
6188    do
6189    {
6190        ++count;
6191        bar.step();
6192
6193        Field *fields = result->Fetch();
6194
6195        uint32 entry = fields[0].GetUInt32();
6196        uint32 bgTypeId  = fields[1].GetUInt32();
6197
6198        mBattleMastersMap[entry] = bgTypeId;
6199
6200    } while( result->NextRow() );
6201
6202    delete result;
6203
6204    sLog.outString();
6205    sLog.outString( ">> Loaded %u battlemaster entries", count );
6206}
6207
6208void ObjectMgr::LoadGameObjectForQuests()
6209{
6210    mGameObjectForQuestSet.clear();                         // need for reload case
6211
6212    uint32 count = 0;
6213
6214    // collect GO entries for GO that must activated
6215    for(uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry)
6216    {
6217        GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(go_entry);
6218        if(!goInfo)
6219            continue;
6220
6221        switch(goInfo->type)
6222        {
6223            // scan GO chest with loot including quest items
6224            case GAMEOBJECT_TYPE_CHEST:
6225            {
6226                uint32 loot_id = GameObject::GetLootId(goInfo);
6227
6228                // find quest loot for GO
6229                if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id))
6230                {
6231                    mGameObjectForQuestSet.insert(go_entry);
6232                    ++count;
6233                }
6234                break;
6235            }
6236            case GAMEOBJECT_TYPE_GOOBER:
6237            {
6238                if(goInfo->goober.questId)                  //quests objects
6239                {
6240                    mGameObjectForQuestSet.insert(go_entry);
6241                    count++;
6242                }
6243                break;
6244            }
6245            default:
6246                break;
6247        }
6248    }
6249
6250    sLog.outString();
6251    sLog.outString( ">> Loaded %u GameObject for quests", count );
6252}
6253
6254bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value)
6255{
6256    // cleanup affected map part for reloading case
6257    for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();)
6258    {
6259        if(itr->first >= min_value && itr->first <= max_value)
6260        {
6261            TrinityStringLocaleMap::iterator itr2 = itr;
6262            ++itr;
6263            mTrinityStringLocaleMap.erase(itr2);
6264        }
6265        else
6266            ++itr;
6267    }
6268
6269    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);
6270
6271    if(!result)
6272    {
6273        barGoLink bar(1);
6274
6275        bar.step();
6276
6277        sLog.outString("");
6278        if(min_value > 0)                                   // error only in case internal strings
6279            sLog.outErrorDb(">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.",table);
6280        else
6281            sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table);
6282        return false;
6283    }
6284
6285    uint32 count = 0;
6286
6287    barGoLink bar(result->GetRowCount());
6288
6289    do
6290    {
6291        Field *fields = result->Fetch();
6292        bar.step();
6293
6294        int32 entry = fields[0].GetInt32();
6295
6296        if(entry==0)
6297        {
6298            sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.",table);
6299            continue;
6300        }
6301        else if(entry < min_value || entry > max_value)
6302        {
6303            int32 start = min_value > 0 ? min_value : max_value;
6304            int32 end   = min_value > 0 ? max_value : min_value;
6305            sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,start,end);
6306            continue;
6307        }
6308
6309        TrinityStringLocale& data = mTrinityStringLocaleMap[entry];
6310
6311        if(data.Content.size() > 0)
6312        {
6313            sLog.outErrorDb("Table `%s` contain data for already loaded entry  %i (from another table?), ignored.",table,entry);
6314            continue;
6315        }
6316
6317        data.Content.resize(1);
6318        ++count;
6319
6320        // 0 -> default, idx in to idx+1
6321        data.Content[0] = fields[1].GetCppString();
6322
6323        for(int i = 1; i < MAX_LOCALE; ++i)
6324        {
6325            std::string str = fields[i+1].GetCppString();
6326            if(!str.empty())
6327            {
6328                int idx = GetOrNewIndexForLocale(LocaleConstant(i));
6329                if(idx >= 0)
6330                {
6331                    // 0 -> default, idx in to idx+1
6332                    if(data.Content.size() <= idx+1)
6333                        data.Content.resize(idx+2);
6334
6335                    data.Content[idx+1] = str;
6336                }
6337            }
6338        }
6339    } while (result->NextRow());
6340
6341    delete result;
6342
6343    sLog.outString();
6344    if(min_value > 0)                                       // internal Trinity strings
6345        sLog.outString( ">> Loaded %u Trinity strings from table %s", count,table);
6346    else
6347        sLog.outString( ">> Loaded %u string templates from %s", count,table);
6348
6349    return true;
6350}
6351
6352const char *ObjectMgr::GetTrinityString(int32 entry, int locale_idx) const
6353{
6354    // locale_idx==-1 -> default, locale_idx >= 0 in to idx+1
6355    // Content[0] always exist if exist TrinityStringLocale
6356    if(TrinityStringLocale const *msl = GetTrinityStringLocale(entry))
6357    {
6358        if(msl->Content.size() > locale_idx+1 && !msl->Content[locale_idx+1].empty())
6359            return msl->Content[locale_idx+1].c_str();
6360        else
6361            return msl->Content[0].c_str();
6362    }
6363
6364    if(entry > 0)
6365        sLog.outErrorDb("Entry %i not found in `trinity_string` table.",entry);
6366    else
6367        sLog.outErrorDb("Trinity string entry %i not found in DB.",entry);
6368    return "<error>";
6369}
6370
6371void ObjectMgr::LoadSpellDisabledEntrys()
6372{
6373    m_DisabledPlayerSpells.clear();                                // need for reload case
6374    m_DisabledCreatureSpells.clear();
6375    QueryResult *result = WorldDatabase.Query("SELECT entry, disable_mask FROM spell_disabled");
6376
6377    uint32 total_count = 0;
6378
6379    if( !result )
6380    {
6381        barGoLink bar( 1 );
6382        bar.step();
6383
6384        sLog.outString();
6385        sLog.outString( ">> Loaded %u disabled spells", total_count );
6386        return;
6387    }
6388
6389    barGoLink bar( result->GetRowCount() );
6390
6391    Field* fields;
6392    do
6393    {
6394        bar.step();
6395        fields = result->Fetch();
6396        uint32 spellid = fields[0].GetUInt32();
6397        if(!sSpellStore.LookupEntry(spellid))
6398        {
6399            sLog.outErrorDb("Spell entry %u from `spell_disabled` doesn't exist in dbc, ignoring.",spellid);
6400            continue;
6401        }
6402        uint32 disable_mask = fields[1].GetUInt32();
6403        if(disable_mask & SPELL_DISABLE_PLAYER)
6404            m_DisabledPlayerSpells.insert(spellid);
6405        if(disable_mask & SPELL_DISABLE_CREATURE)
6406            m_DisabledCreatureSpells.insert(spellid);
6407        ++total_count;
6408   } while ( result->NextRow() );
6409
6410    delete result;
6411
6412    sLog.outString();
6413    sLog.outString( ">> Loaded %u disabled spells from `spell_disabled`", total_count);
6414}
6415
6416void ObjectMgr::LoadFishingBaseSkillLevel()
6417{
6418    mFishingBaseForArea.clear();                            // for relaod case
6419
6420    uint32 count = 0;
6421    QueryResult *result = WorldDatabase.Query("SELECT entry,skill FROM skill_fishing_base_level");
6422
6423    if( !result )
6424    {
6425        barGoLink bar( 1 );
6426
6427        bar.step();
6428
6429        sLog.outString();
6430        sLog.outErrorDb(">> Loaded `skill_fishing_base_level`, table is empty!");
6431        return;
6432    }
6433
6434    barGoLink bar( result->GetRowCount() );
6435
6436    do
6437    {
6438        bar.step();
6439
6440        Field *fields = result->Fetch();
6441        uint32 entry  = fields[0].GetUInt32();
6442        int32 skill   = fields[1].GetInt32();
6443
6444        AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry);
6445        if(!fArea)
6446        {
6447            sLog.outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist",entry);
6448            continue;
6449        }
6450
6451        mFishingBaseForArea[entry] = skill;
6452        ++count;
6453    }
6454    while (result->NextRow());
6455
6456    delete result;
6457
6458    sLog.outString();
6459    sLog.outString( ">> Loaded %u areas for fishing base skill level", count );
6460}
6461
6462// Searches for the same condition already in Conditions store
6463// Returns Id if found, else adds it to Conditions and returns Id
6464uint16 ObjectMgr::GetConditionId( ConditionType condition, uint32 value1, uint32 value2 )
6465{
6466    PlayerCondition lc = PlayerCondition(condition, value1, value2);
6467    for (uint16 i=0; i < mConditions.size(); ++i)
6468    {
6469        if (lc == mConditions[i])
6470            return i;
6471    }
6472
6473    mConditions.push_back(lc);
6474
6475    if(mConditions.size() > 0xFFFF)
6476    {
6477        sLog.outError("Conditions store overflow! Current and later loaded conditions will ignored!");
6478        return 0;
6479    }
6480
6481    return mConditions.size() - 1;
6482}
6483
6484bool ObjectMgr::CheckDeclinedNames( std::wstring mainpart, DeclinedName const& names )
6485{
6486    for(int i =0; i < MAX_DECLINED_NAME_CASES; ++i)
6487    {
6488        std::wstring wname;
6489        if(!Utf8toWStr(names.name[i],wname))
6490            return false;
6491
6492        if(mainpart!=GetMainPartOfName(wname,i+1))
6493            return false;
6494    }
6495    return true;
6496}
6497
6498const char* ObjectMgr::GetAreaTriggerScriptName(uint32 id)
6499{
6500    AreaTriggerScriptMap::const_iterator i = mAreaTriggerScripts.find(id);
6501    if(i!= mAreaTriggerScripts.end())
6502        return i->second.c_str();
6503    return "";
6504}
6505
6506// Checks if player meets the condition
6507bool PlayerCondition::Meets(Player const * player) const
6508{
6509    if( !player )
6510        return false;                                       // player not present, return false
6511
6512    switch (condition)
6513    {
6514        case CONDITION_NONE:
6515            return true;                                    // empty condition, always met
6516        case CONDITION_AURA:
6517            return player->HasAura(value1, value2);
6518        case CONDITION_ITEM:
6519            return player->HasItemCount(value1, value2);
6520        case CONDITION_ITEM_EQUIPPED:
6521            return player->GetItemOrItemWithGemEquipped(value1) != NULL;
6522        case CONDITION_ZONEID:
6523            return player->GetZoneId() == value1;
6524        case CONDITION_REPUTATION_RANK:
6525        {
6526            FactionEntry const* faction = sFactionStore.LookupEntry(value1);
6527            return faction && player->GetReputationRank(faction) >= value2;
6528        }
6529        case CONDITION_TEAM:
6530            return player->GetTeam() == value1;
6531        case CONDITION_SKILL:
6532            return player->HasSkill(value1) && player->GetBaseSkillValue(value1) >= value2;
6533        case CONDITION_QUESTREWARDED:
6534            return player->GetQuestRewardStatus(value1);
6535        case CONDITION_QUESTTAKEN:
6536        {
6537            QuestStatus status = player->GetQuestStatus(value1);
6538            return (status == QUEST_STATUS_INCOMPLETE);
6539        }
6540        case CONDITION_AD_COMMISSION_AURA:
6541        {
6542            Unit::AuraMap const& auras = player->GetAuras();
6543            for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6544                if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual==3580)
6545                    return true;
6546            return false;
6547        }
6548        default:
6549            return false;
6550    }
6551}
6552
6553// Verification of condition values validity
6554bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 value2)
6555{
6556    if( condition >= MAX_CONDITION)                         // Wrong condition type
6557    {
6558        sLog.outErrorDb("Condition has bad type of %u, skipped ", condition );
6559        return false;
6560    }
6561
6562    switch (condition)
6563    {
6564        case CONDITION_AURA:
6565        {
6566            if(!sSpellStore.LookupEntry(value1))
6567            {
6568                sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1);
6569                return false;
6570            }
6571            if(value2 > 2)
6572            {
6573                sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2);
6574                return false;
6575            }
6576            break;
6577        }
6578        case CONDITION_ITEM:
6579        {
6580            ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
6581            if(!proto)
6582            {
6583                sLog.outErrorDb("Item condition requires to have non existing item (%u), skipped", value1);
6584                return false;
6585            }
6586            break;
6587        }
6588        case CONDITION_ITEM_EQUIPPED:
6589        {
6590            ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
6591            if(!proto)
6592            {
6593                sLog.outErrorDb("ItemEquipped condition requires to have non existing item (%u) equipped, skipped", value1);
6594                return false;
6595            }
6596            break;
6597        }
6598        case CONDITION_ZONEID:
6599        {
6600            AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(value1);
6601            if(!areaEntry)
6602            {
6603                sLog.outErrorDb("Zone condition requires to be in non existing area (%u), skipped", value1);
6604                return false;
6605            }
6606            if(areaEntry->zone != 0)
6607            {
6608                sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", value1);
6609                return false;
6610            }
6611            break;
6612        }
6613        case CONDITION_REPUTATION_RANK:
6614        {
6615            FactionEntry const* factionEntry = sFactionStore.LookupEntry(value1);
6616            if(!factionEntry)
6617            {
6618                sLog.outErrorDb("Reputation condition requires to have reputation non existing faction (%u), skipped", value1);
6619                return false;
6620            }
6621            break;
6622        }
6623        case CONDITION_TEAM:
6624        {
6625            if (value1 != ALLIANCE && value1 != HORDE)
6626            {
6627                sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", value1);
6628                return false;
6629            }
6630            break;
6631        }
6632        case CONDITION_SKILL:
6633        {
6634            SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(value1);
6635            if (!pSkill)
6636            {
6637                sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", value1);
6638                return false;
6639            }
6640            if (value2 < 1 || value2 > sWorld.GetConfigMaxSkillValue() )
6641            {
6642                sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", value2);
6643                return false;
6644            }
6645            break;
6646        }
6647        case CONDITION_QUESTREWARDED:
6648        case CONDITION_QUESTTAKEN:
6649        {
6650            Quest const *Quest = objmgr.GetQuestTemplate(value1);
6651            if (!Quest)
6652            {
6653                sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", value1);
6654                return false;
6655            }
6656            if(value2)
6657                sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
6658            break;
6659        }
6660        case CONDITION_AD_COMMISSION_AURA:
6661        {
6662            if(value1)
6663                sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", value1);
6664            if(value2)
6665                sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
6666            break;
6667        }
6668    }
6669    return true;
6670}
6671
6672SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
6673{
6674    switch(pSkill->categoryId)
6675    {
6676        case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE;
6677        case SKILL_CATEGORY_WEAPON:
6678            if(pSkill->id!=SKILL_FIST_WEAPONS)
6679                return SKILL_RANGE_LEVEL;
6680            else
6681                return SKILL_RANGE_MONO;
6682        case SKILL_CATEGORY_ARMOR:
6683        case SKILL_CATEGORY_CLASS:
6684            if(pSkill->id != SKILL_POISONS && pSkill->id != SKILL_LOCKPICKING)
6685                return SKILL_RANGE_MONO;
6686            else
6687                return SKILL_RANGE_LEVEL;
6688        case SKILL_CATEGORY_SECONDARY:
6689        case SKILL_CATEGORY_PROFESSION:
6690            // not set skills for professions and racial abilities
6691            if(IsProfessionSkill(pSkill->id))
6692                return SKILL_RANGE_RANK;
6693            else if(racial)
6694                return SKILL_RANGE_NONE;
6695            else
6696                return SKILL_RANGE_MONO;
6697        default:
6698        case SKILL_CATEGORY_ATTRIBUTES:                     //not found in dbc
6699        case SKILL_CATEGORY_NOT_DISPLAYED:                  //only GENEREC(DND)
6700            return SKILL_RANGE_NONE;
6701    }
6702}
6703
6704void ObjectMgr::LoadGameTele()
6705{
6706    m_GameTeleMap.clear();                                  // for relaod case
6707
6708    uint32 count = 0;
6709    QueryResult *result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele");
6710
6711    if( !result )
6712    {
6713        barGoLink bar( 1 );
6714
6715        bar.step();
6716
6717        sLog.outString();
6718        sLog.outErrorDb(">> Loaded `game_tele`, table is empty!");
6719        return;
6720    }
6721
6722    barGoLink bar( result->GetRowCount() );
6723
6724    do
6725    {
6726        bar.step();
6727
6728        Field *fields = result->Fetch();
6729
6730        uint32 id         = fields[0].GetUInt32();
6731
6732        GameTele gt;
6733
6734        gt.position_x     = fields[1].GetFloat();
6735        gt.position_y     = fields[2].GetFloat();
6736        gt.position_z     = fields[3].GetFloat();
6737        gt.orientation    = fields[4].GetFloat();
6738        gt.mapId          = fields[5].GetUInt32();
6739        gt.name           = fields[6].GetCppString();
6740
6741        if(!MapManager::IsValidMapCoord(gt.mapId,gt.position_x,gt.position_y,gt.position_z,gt.orientation))
6742        {
6743            sLog.outErrorDb("Wrong position for id %u (name: %s) in `game_tele` table, ignoring.",id,gt.name.c_str());
6744            continue;
6745        }
6746
6747        if(!Utf8toWStr(gt.name,gt.wnameLow))
6748        {
6749            sLog.outErrorDb("Wrong UTF8 name for id %u in `game_tele` table, ignoring.",id);
6750            continue;
6751        }
6752
6753        wstrToLower( gt.wnameLow );
6754
6755        m_GameTeleMap[id] = gt;
6756
6757        ++count;
6758    }
6759    while (result->NextRow());
6760
6761    delete result;
6762
6763    sLog.outString();
6764    sLog.outString( ">> Loaded %u game tele's", count );
6765}
6766
6767GameTele const* ObjectMgr::GetGameTele(std::string name) const
6768{
6769    // explicit name case
6770    std::wstring wname;
6771    if(!Utf8toWStr(name,wname))
6772        return false;
6773
6774    // converting string that we try to find to lower case
6775    wstrToLower( wname );
6776
6777    for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
6778        if(itr->second.wnameLow == wname)
6779            return &itr->second;
6780
6781    return NULL;
6782}
6783
6784bool ObjectMgr::AddGameTele(GameTele& tele)
6785{
6786    // find max id
6787    uint32 new_id = 0;
6788    for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
6789        if(itr->first > new_id)
6790            new_id = itr->first;
6791   
6792    // use next
6793    ++new_id;
6794
6795    if(!Utf8toWStr(tele.name,tele.wnameLow))
6796        return false;
6797
6798    wstrToLower( tele.wnameLow );
6799
6800    m_GameTeleMap[new_id] = tele;
6801
6802    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')",
6803        new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str());
6804}
6805
6806bool ObjectMgr::DeleteGameTele(std::string name)
6807{
6808    // explicit name case
6809    std::wstring wname;
6810    if(!Utf8toWStr(name,wname))
6811        return false;
6812
6813    // converting string that we try to find to lower case
6814    wstrToLower( wname );
6815
6816    for(GameTeleMap::iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
6817    {
6818        if(itr->second.wnameLow == wname)
6819        {
6820            WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str());
6821            m_GameTeleMap.erase(itr);
6822            return true;
6823        }
6824    }
6825
6826    return false;
6827}
6828
6829void ObjectMgr::LoadTrainerSpell()
6830{
6831    // For reload case
6832    for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr)
6833        itr->second.Clear();
6834    m_mCacheTrainerSpellMap.clear();
6835
6836    std::set<uint32> skip_trainers;
6837
6838    QueryResult *result = WorldDatabase.PQuery("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer");
6839
6840    if( !result )
6841    {
6842        barGoLink bar( 1 );
6843
6844        bar.step();
6845
6846        sLog.outString();
6847        sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!");
6848        return;
6849    }
6850
6851    barGoLink bar( result->GetRowCount() );
6852
6853    uint32 count = 0;
6854    do
6855    {
6856        bar.step();
6857
6858        Field* fields = result->Fetch();
6859
6860        uint32 entry  = fields[0].GetUInt32();
6861        uint32 spell  = fields[1].GetUInt32();
6862
6863        CreatureInfo const* cInfo = GetCreatureTemplate(entry);
6864
6865        if(!cInfo)
6866        {
6867            sLog.outErrorDb("Table `npc_trainer` have entry for not existed creature template (Entry: %u), ignore", entry);
6868            continue;
6869        }
6870
6871        if(!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
6872        {
6873            if(skip_trainers.count(entry) == 0)
6874            {
6875                sLog.outErrorDb("Table `npc_trainer` have data for not creature template (Entry: %u) without trainer flag, ignore", entry);
6876                skip_trainers.insert(entry);
6877            }
6878            continue;
6879        }
6880
6881        SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell);
6882        if(!spellinfo)
6883        {
6884            sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u ) has non existing spell %u, ignore", entry,spell);
6885            continue;
6886        }
6887
6888        if(!SpellMgr::IsSpellValid(spellinfo))
6889        {
6890            sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell);
6891            continue;
6892        }
6893
6894        TrainerSpell* pTrainerSpell = new TrainerSpell();
6895        pTrainerSpell->spell         = spell;
6896        pTrainerSpell->spellcost     = fields[2].GetUInt32();
6897        pTrainerSpell->reqskill      = fields[3].GetUInt32();
6898        pTrainerSpell->reqskillvalue = fields[4].GetUInt32();
6899        pTrainerSpell->reqlevel      = fields[5].GetUInt32();
6900
6901        if(!pTrainerSpell->reqlevel)
6902            pTrainerSpell->reqlevel = spellinfo->spellLevel;
6903
6904
6905        TrainerSpellData& data = m_mCacheTrainerSpellMap[entry];
6906
6907        if(SpellMgr::IsProfessionSpell(spell))
6908            data.trainerType = 2;
6909
6910        data.spellList.push_back(pTrainerSpell);
6911        ++count;
6912
6913    } while (result->NextRow());
6914    delete result;
6915
6916    sLog.outString();
6917    sLog.outString( ">> Loaded Trainers %d", count );
6918}
6919
6920void ObjectMgr::LoadVendors()
6921{
6922    // For reload case
6923    for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr)
6924        itr->second.Clear();
6925    m_mCacheVendorItemMap.clear();
6926
6927    std::set<uint32> skip_vendors;
6928
6929    QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor");
6930    if( !result )
6931    {
6932        barGoLink bar( 1 );
6933
6934        bar.step();
6935
6936        sLog.outString();
6937        sLog.outErrorDb(">> Loaded `npc_vendor`, table is empty!");
6938        return;
6939    }
6940
6941    barGoLink bar( result->GetRowCount() );
6942
6943    uint32 count = 0;
6944    do
6945    {
6946        bar.step();
6947        Field* fields = result->Fetch();
6948
6949        uint32 entry        = fields[0].GetUInt32();
6950        uint32 item_id      = fields[1].GetUInt32();
6951        uint32 maxcount     = fields[2].GetUInt32();
6952        uint32 incrtime     = fields[3].GetUInt32();
6953        uint32 ExtendedCost = fields[4].GetUInt32();
6954
6955        if(!IsVendorItemValid(entry,item_id,maxcount,incrtime,ExtendedCost,NULL,&skip_vendors))
6956            continue;
6957
6958        VendorItemData& vList = m_mCacheVendorItemMap[entry];
6959
6960        vList.AddItem(item_id,maxcount,incrtime,ExtendedCost);
6961        ++count;
6962
6963    } while (result->NextRow());
6964    delete result;
6965
6966    sLog.outString();
6967    sLog.outString( ">> Loaded %d Vendors ", count );
6968}
6969
6970void ObjectMgr::LoadNpcTextId()
6971{
6972
6973    m_mCacheNpcTextIdMap.clear();
6974
6975    QueryResult* result = WorldDatabase.PQuery("SELECT npc_guid, textid FROM npc_gossip");
6976    if( !result )
6977    {
6978        barGoLink bar( 1 );
6979
6980        bar.step();
6981
6982        sLog.outString();
6983        sLog.outErrorDb(">> Loaded `npc_gossip`, table is empty!");
6984        return;
6985    }
6986
6987    barGoLink bar( result->GetRowCount() );
6988
6989    uint32 count = 0;
6990    uint32 guid,textid;
6991    do
6992    {
6993        bar.step();
6994
6995        Field* fields = result->Fetch();
6996
6997        guid   = fields[0].GetUInt32();
6998        textid = fields[1].GetUInt32();
6999
7000        if (!GetCreatureData(guid))
7001        {
7002            sLog.outErrorDb("Table `npc_gossip` have not existed creature (GUID: %u) entry, ignore. ",guid);
7003            continue;
7004        }
7005        if (!GetGossipText(textid))
7006        {
7007            sLog.outErrorDb("Table `npc_gossip` for creature (GUID: %u) have wrong Textid (%u), ignore. ", guid, textid);
7008            continue;
7009        }
7010
7011        m_mCacheNpcTextIdMap[guid] = textid ;
7012        ++count;
7013
7014    } while (result->NextRow());
7015    delete result;
7016
7017    sLog.outString();
7018    sLog.outString( ">> Loaded %d NpcTextId ", count );
7019}
7020
7021void ObjectMgr::AddVendorItem( uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 extendedcost, bool savetodb)
7022{
7023    VendorItemData& vList = m_mCacheVendorItemMap[entry];
7024    vList.AddItem(item,maxcount,incrtime,extendedcost);
7025
7026    if(savetodb) WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')",entry, item, maxcount,incrtime,extendedcost);
7027}
7028
7029bool ObjectMgr::RemoveVendorItem( uint32 entry,uint32 item, bool savetodb)
7030{
7031    CacheVendorItemMap::iterator  iter = m_mCacheVendorItemMap.find(entry);
7032    if(iter == m_mCacheVendorItemMap.end())
7033        return false;
7034
7035    if(!iter->second.FindItem(item))
7036        return false;
7037
7038    iter->second.RemoveItem(item);
7039    if(savetodb) WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item);
7040    return true;
7041}
7042
7043bool ObjectMgr::IsVendorItemValid( uint32 vendor_entry, uint32 item_id, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set<uint32>* skip_vendors, uint32 ORnpcflag ) const
7044{
7045    CreatureInfo const* cInfo = GetCreatureTemplate(vendor_entry);
7046    if(!cInfo)
7047    {
7048        if(pl)
7049            ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
7050        else
7051            sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not existed creature template (Entry: %u), ignore", vendor_entry);
7052        return false;
7053    }
7054
7055    if(!((cInfo->npcflag | ORnpcflag) & UNIT_NPC_FLAG_VENDOR))
7056    {
7057        if(!skip_vendors || skip_vendors->count(vendor_entry)==0)
7058        {
7059            if(pl)
7060                ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
7061            else
7062                sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not creature template (Entry: %u) without vendor flag, ignore", vendor_entry);
7063
7064            if(skip_vendors)
7065                skip_vendors->insert(vendor_entry);
7066        }
7067        return false;
7068    }
7069
7070    if(!GetItemPrototype(item_id))
7071    {
7072        if(pl)
7073            ChatHandler(pl).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id);
7074        else
7075            sLog.outErrorDb("Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore",vendor_entry,item_id);
7076        return false;
7077    }
7078
7079    if(ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost))
7080    {
7081        if(pl)
7082            ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST,ExtendedCost);
7083        else
7084            sLog.outErrorDb("Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore",item_id,ExtendedCost,vendor_entry);
7085        return false;
7086    }
7087
7088    if(maxcount > 0 && incrtime == 0)
7089    {
7090        if(pl)
7091            ChatHandler(pl).PSendSysMessage("MaxCount!=0 (%u) but IncrTime==0", maxcount);
7092        else
7093            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);
7094        return false;
7095    }
7096    else if(maxcount==0 && incrtime > 0)
7097    {
7098        if(pl)
7099            ChatHandler(pl).PSendSysMessage("MaxCount==0 but IncrTime<>=0");
7100        else
7101            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);
7102        return false;
7103    }
7104
7105    VendorItemData const* vItems = GetNpcVendorItemList(vendor_entry);
7106    if(!vItems)
7107        return true;                                        // later checks for non-empty lists
7108
7109    if(vItems->FindItem(item_id))
7110    {
7111        if(pl)
7112            ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST,item_id);
7113        else
7114            sLog.outErrorDb( "Table `(game_event_)npc_vendor` has duplicate items %u for vendor (Entry: %u), ignore", item_id, vendor_entry);
7115        return false;
7116    }
7117
7118    if(vItems->GetItemCount() >= MAX_VENDOR_ITEMS)
7119    {
7120        if(pl)
7121            ChatHandler(pl).SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS);
7122        else
7123            sLog.outErrorDb( "Table `npc_vendor` has too many items (%u >= %i) for vendor (Entry: %u), ignore", vItems->GetItemCount(), MAX_VENDOR_ITEMS, vendor_entry);
7124        return false;
7125    }
7126
7127    return true;
7128}
7129
7130// Functions for scripting access
7131const char* GetAreaTriggerScriptNameById(uint32 id)
7132{
7133    return objmgr.GetAreaTriggerScriptName(id);
7134}
7135
7136bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value)
7137{
7138    if(start_value >= 0 || start_value <= end_value)        // start/end reversed for negative values
7139    {
7140        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());
7141        start_value = -1;
7142        end_value = std::numeric_limits<int32>::min();
7143    }
7144
7145    // for scripting localized strings allowed use _only_ negative entries
7146    return objmgr.LoadTrinityStrings(db,table,end_value,start_value);
7147}
Note: See TracBrowser for help on using the browser.