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

Revision 85, 249.4 kB (checked in by yumileroy, 17 years ago)

[svn] Implement a new table (spell_disabled) to allow disabling some spells for players and / or creatures. To disable a spell for a players and pets, set 20 in the disable_mask, to disable for creatures, set 21. The comment field is optional. Original patch provided by Craker.

Original author: w12x
Date: 2008-10-21 03:58:38-05:00

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