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

Revision 44, 248.6 kB (checked in by yumileroy, 17 years ago)

[svn] * Merge Temp dev SVN with Assembla.
* Changes include:

  • Implementation of w12x's Outdoor PvP and Game Event Systems.
  • Temporary removal of IRC Chat Bot (until infinite loop when disabled is fixed).
  • All mangos -> trinity (to convert your mangos_string table, please run mangos_string_to_trinity_string.sql).
  • Improved Config cleanup.
  • And many more changes.

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