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

Revision 126, 252.9 kB (checked in by yumileroy, 17 years ago)

[svn] * Fixed startup error flood if creature model id is 0
* Fixed totems using proper model ids broken after recent change
* Set pet grid activity state to that of caster upon summoning
* Fix a possible crash in ObjectAccessor?
note to self: don't commit anything without 3 days testing. ever. after this one ofc.

Original author: w12x
Date: 2008-10-27 15:28:04-05:00

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