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

Revision 2, 232.0 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

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