aboutsummaryrefslogtreecommitdiff
path: root/src/game/ObjectMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/ObjectMgr.cpp')
-rw-r--r--src/game/ObjectMgr.cpp1490
1 files changed, 1035 insertions, 455 deletions
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 227b0f90f28..a8b45738696 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,14 +30,13 @@
#include "SpellMgr.h"
#include "UpdateMask.h"
#include "World.h"
-#include "WorldSession.h"
#include "Group.h"
#include "Guild.h"
#include "ArenaTeam.h"
#include "Transports.h"
#include "ProgressBar.h"
#include "Language.h"
-#include "GameEvent.h"
+#include "GameEventMgr.h"
#include "Spell.h"
#include "Chat.h"
#include "AccountMgr.h"
@@ -116,6 +115,7 @@ ObjectMgr::ObjectMgr()
m_hiCharGuid = 1;
m_hiCreatureGuid = 1;
m_hiPetGuid = 1;
+ m_hiVehicleGuid = 1;
m_hiItemGuid = 1;
m_hiGoGuid = 1;
m_hiDoGuid = 1;
@@ -127,14 +127,6 @@ ObjectMgr::ObjectMgr()
m_arenaTeamId = 1;
m_auctionid = 1;
- mGuildBankTabPrice.resize(GUILD_BANK_MAX_TABS);
- mGuildBankTabPrice[0] = 100;
- mGuildBankTabPrice[1] = 250;
- mGuildBankTabPrice[2] = 500;
- mGuildBankTabPrice[3] = 1000;
- mGuildBankTabPrice[4] = 2500;
- mGuildBankTabPrice[5] = 5000;
-
// Only zero condition left, others will be added while loading DB tables
mConditions.resize(1);
}
@@ -142,24 +134,10 @@ ObjectMgr::ObjectMgr()
ObjectMgr::~ObjectMgr()
{
for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++i )
- {
delete i->second;
- }
- mQuestTemplates.clear( );
-
- for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++i )
- {
- delete i->second;
- }
- mGossipText.clear( );
-
- mAreaTriggers.clear();
for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++i )
- {
delete[] i->second;
- }
- petInfo.clear();
// free only if loaded
for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
@@ -251,7 +229,7 @@ Group * ObjectMgr::GetGroupByLeader(const uint64 &guid) const
return NULL;
}
-Guild * ObjectMgr::GetGuildById(const uint32 GuildId) const
+Guild * ObjectMgr::GetGuildById(uint32 GuildId) const
{
GuildMap::const_iterator itr = mGuildMap.find(GuildId);
if (itr != mGuildMap.end())
@@ -269,7 +247,7 @@ Guild * ObjectMgr::GetGuildByName(const std::string& guildname) const
return NULL;
}
-std::string ObjectMgr::GetGuildNameById(const uint32 GuildId) const
+std::string ObjectMgr::GetGuildNameById(uint32 GuildId) const
{
GuildMap::const_iterator itr = mGuildMap.find(GuildId);
if (itr != mGuildMap.end())
@@ -296,7 +274,8 @@ void ObjectMgr::RemoveGuild(uint32 Id)
{
mGuildMap.erase(Id);
}
-ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 arenateamid) const
+
+ArenaTeam* ObjectMgr::GetArenaTeamById(uint32 arenateamid) const
{
ArenaTeamMap::const_iterator itr = mArenaTeamMap.find(arenateamid);
if (itr != mArenaTeamMap.end())
@@ -350,7 +329,7 @@ void ObjectMgr::LoadCreatureLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 creature locale strings. DB table `locales_creature` is empty.");
return;
}
@@ -398,7 +377,7 @@ void ObjectMgr::LoadCreatureLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu creature locale strings", (unsigned long)mCreatureLocaleMap.size() );
}
void ObjectMgr::LoadNpcOptionLocales()
@@ -418,7 +397,7 @@ void ObjectMgr::LoadNpcOptionLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 npc_option locale strings. DB table `locales_npc_option` is empty.");
return;
}
@@ -466,13 +445,64 @@ void ObjectMgr::LoadNpcOptionLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u npc_option locale strings", mNpcOptionLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu npc_option locale strings", (unsigned long)mNpcOptionLocaleMap.size() );
+}
+
+void ObjectMgr::LoadPointOfInterestLocales()
+{
+ mPointOfInterestLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,icon_name_loc1,icon_name_loc2,icon_name_loc3,icon_name_loc4,icon_name_loc5,icon_name_loc6,icon_name_loc7,icon_name_loc8 FROM locales_points_of_interest");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded 0 points_of_interest locale strings. DB table `locales_points_of_interest` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ PointOfInterestLocale& data = mPointOfInterestLocaleMap[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[i].GetCppString();
+ if(str.empty())
+ continue;
+
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.IconName.size() <= idx)
+ data.IconName.resize(idx+1);
+
+ data.IconName[idx] = str;
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %lu points_of_interest locale strings", (unsigned long)mPointOfInterestLocaleMap.size() );
}
struct SQLCreatureLoader : public SQLStorageLoaderBase<SQLCreatureLoader>
{
template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
+ void convert_from_str(uint32 /*field_pos*/, char *src, D &dst)
{
dst = D(objmgr.GetScriptId(src));
}
@@ -553,6 +583,18 @@ void ObjectMgr::LoadCreatureTemplates()
continue;
}
+ if(heroicInfo->AIName && *heroicInfo->AIName)
+ {
+ sLog.outErrorDb("Heroic mode creature (Entry: %u) has `AIName`, but in any case will used normal mode creature (Entry: %u) AIName.",cInfo->HeroicEntry,i);
+ continue;
+ }
+
+ if(heroicInfo->ScriptID)
+ {
+ sLog.outErrorDb("Heroic mode creature (Entry: %u) has `ScriptName`, but in any case will used normal mode creature (Entry: %u) ScriptName.",cInfo->HeroicEntry,i);
+ continue;
+ }
+
hasHeroicEntries.insert(i);
heroicEntries.insert(cInfo->HeroicEntry);
}
@@ -602,6 +644,19 @@ void ObjectMgr::LoadCreatureTemplates()
if((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type);
+ if(cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`",cInfo->Entry,cInfo->type);
+ const_cast<CreatureInfo*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
+ }
+
+ // must exist or used hidden but used in data horse case
+ if(cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM )
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`",cInfo->Entry,cInfo->family);
+ const_cast<CreatureInfo*>(cInfo)->family = 0;
+ }
+
if(cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
{
sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType);
@@ -615,6 +670,15 @@ void ObjectMgr::LoadCreatureTemplates()
sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId);
}
+ for(int j = 0; j < CREATURE_MAX_SPELLS; ++j)
+ {
+ if(cInfo->spells[j] && !sSpellStore.LookupEntry(cInfo->spells[j]))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing Spell%d (%u), set to 0", cInfo->Entry, j+1,cInfo->spells[j]);
+ const_cast<CreatureInfo*>(cInfo)->spells[j] = 0;
+ }
+ }
+
if(cInfo->MovementType >= MAX_DB_MOTION_TYPE)
{
sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType);
@@ -763,8 +827,47 @@ void ObjectMgr::LoadEquipmentTemplates()
{
sEquipmentStorage.Load();
+ for(uint32 i=0; i< sEquipmentStorage.MaxEntry; ++i)
+ {
+ EquipmentInfo const* eqInfo = sEquipmentStorage.LookupEntry<EquipmentInfo>(i);
+
+ if(!eqInfo)
+ continue;
+
+ for(uint8 j=0; j<3; j++)
+ {
+ if(!eqInfo->equipentry[j])
+ continue;
+
+ ItemEntry const *dbcitem = sItemStore.LookupEntry(eqInfo->equipentry[j]);
+
+ if(!dbcitem)
+ {
+ sLog.outErrorDb("Unknown item (entry=%u) in creature_equip_template.equipentry%u for entry = %u, forced to 0.", eqInfo->equipentry[j], j+1, i);
+ const_cast<EquipmentInfo*>(eqInfo)->equipentry[j] = 0;
+ continue;
+ }
+
+ if(dbcitem->InventoryType != INVTYPE_WEAPON &&
+ dbcitem->InventoryType != INVTYPE_SHIELD &&
+ dbcitem->InventoryType != INVTYPE_RANGED &&
+ dbcitem->InventoryType != INVTYPE_2HWEAPON &&
+ dbcitem->InventoryType != INVTYPE_WEAPONMAINHAND &&
+ dbcitem->InventoryType != INVTYPE_WEAPONOFFHAND &&
+ dbcitem->InventoryType != INVTYPE_HOLDABLE &&
+ dbcitem->InventoryType != INVTYPE_THROWN &&
+ dbcitem->InventoryType != INVTYPE_RANGEDRIGHT)
+ {
+ sLog.outErrorDb("Item (entry=%u) in creature_equip_template.equipentry%u for entry = %u is not equipable in a hand, forced to 0.", eqInfo->equipentry[j], j+1, i);
+ const_cast<EquipmentInfo*>(eqInfo)->equipentry[j] = 0;
+ }
+ }
+ }
sLog.outString( ">> Loaded %u equipment template", sEquipmentStorage.RecordCount );
sLog.outString();
+
+ // This DBC is currently only used for item templates and creature equipments checks.
+ sItemStore.Clear();
}
CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid)
@@ -924,9 +1027,10 @@ void ObjectMgr::LoadCreatures()
QueryResult *result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid,"
// 4 5 6 7 8 9 10 11
"equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint,"
- // 12 13 14 15 16 17
- "curhealth, curmana, DeathState, MovementType, spawnMask, event "
- "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid");
+ // 12 13 14 15 16 17 18 19
+ "curhealth, curmana, DeathState, MovementType, spawnMask, phaseMask, event, pool_entry "
+ "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid "
+ "LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid");
if(!result)
{
@@ -934,7 +1038,7 @@ void ObjectMgr::LoadCreatures()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty.");
return;
}
@@ -953,11 +1057,19 @@ void ObjectMgr::LoadCreatures()
Field *fields = result->Fetch();
bar.step();
- uint32 guid = fields[0].GetUInt32();
+ uint32 guid = fields[ 0].GetUInt32();
+ uint32 entry = fields[ 1].GetUInt32();
+
+ CreatureInfo const* cInfo = GetCreatureTemplate(entry);
+ if(!cInfo)
+ {
+ sLog.outErrorDb("Table `creature` has creature (GUID: %u) with non existing creature entry %u, skipped.", guid, entry);
+ continue;
+ }
CreatureData& data = mCreatureDataMap[guid];
- data.id = fields[ 1].GetUInt32();
+ data.id = entry;
data.mapid = fields[ 2].GetUInt32();
data.displayid = fields[ 3].GetUInt32();
data.equipmentId = fields[ 4].GetUInt32();
@@ -973,14 +1085,9 @@ void ObjectMgr::LoadCreatures()
data.is_dead = fields[14].GetBool();
data.movementType = fields[15].GetUInt8();
data.spawnMask = fields[16].GetUInt8();
- int16 gameEvent = fields[17].GetInt16();
-
- CreatureInfo const* cInfo = GetCreatureTemplate(data.id);
- if(!cInfo)
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u) with not existed creature entry %u, skipped.",guid,data.id );
- continue;
- }
+ data.phaseMask = fields[17].GetUInt16();
+ int16 gameEvent = fields[18].GetInt16();
+ int16 PoolId = fields[19].GetInt16();
if(heroicCreatures.find(data.id)!=heroicCreatures.end())
{
@@ -1003,6 +1110,13 @@ void ObjectMgr::LoadCreatures()
data.curhealth = cInfo->minhealth;
}
+ if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
+ {
+ MapEntry const* map = sMapStore.LookupEntry(data.mapid);
+ if(!map || !map->IsDungeon())
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id);
+ }
+
if(data.curmana < cInfo->minmana)
{
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 );
@@ -1031,8 +1145,15 @@ void ObjectMgr::LoadCreatures()
}
}
- if (gameEvent==0) // if not this is to be managed by GameEvent System
+ if(data.phaseMask==0)
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.",guid,data.id );
+ data.phaseMask = 1;
+ }
+
+ if (gameEvent==0 && PoolId==0) // if not this is to be managed by GameEvent System or Pool system
AddCreatureToGrid(guid, &data);
+
++count;
} while (result->NextRow());
@@ -1040,7 +1161,7 @@ void ObjectMgr::LoadCreatures()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u creatures", mCreatureDataMap.size() );
+ sLog.outString( ">> Loaded %lu creatures", (unsigned long)mCreatureDataMap.size() );
}
void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data)
@@ -1081,9 +1202,10 @@ void ObjectMgr::LoadGameobjects()
// 0 1 2 3 4 5 6
QueryResult *result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation,"
- // 7 8 9 10 11 12 13 14 15
- "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, event "
- "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid");
+ // 7 8 9 10 11 12 13 14 15 16 17
+ "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, event, pool_entry "
+ "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid "
+ "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid");
if(!result)
{
@@ -1103,11 +1225,19 @@ void ObjectMgr::LoadGameobjects()
Field *fields = result->Fetch();
bar.step();
- uint32 guid = fields[0].GetUInt32();
+ uint32 guid = fields[ 0].GetUInt32();
+ uint32 entry = fields[ 1].GetUInt32();
+
+ GameObjectInfo const* gInfo = GetGameObjectInfo(entry);
+ if(!gInfo)
+ {
+ sLog.outErrorDb("Table `gameobject` has gameobject (GUID: %u) with non existing gameobject entry %u, skipped.", guid, entry);
+ continue;
+ }
GameObjectData& data = mGameObjectDataMap[guid];
- data.id = fields[ 1].GetUInt32();
+ data.id = entry;
data.mapid = fields[ 2].GetUInt32();
data.posX = fields[ 3].GetFloat();
data.posY = fields[ 4].GetFloat();
@@ -1119,19 +1249,46 @@ void ObjectMgr::LoadGameobjects()
data.rotation3 = fields[10].GetFloat();
data.spawntimesecs = fields[11].GetInt32();
data.animprogress = fields[12].GetUInt32();
- data.go_state = fields[13].GetUInt32();
data.ArtKit = 0;
+
+ uint32 go_state = fields[13].GetUInt32();
+ if (go_state >= MAX_GO_STATE)
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid `state` (%u) value, skip",guid,data.id,go_state);
+ continue;
+ }
+ data.go_state = GOState(go_state);
+
data.spawnMask = fields[14].GetUInt8();
- int16 gameEvent = fields[15].GetInt16();
+ data.phaseMask = fields[15].GetUInt16();
+ int16 gameEvent = fields[16].GetInt16();
+ int16 PoolId = fields[17].GetInt16();
- GameObjectInfo const* gInfo = GetGameObjectInfo(data.id);
- if(!gInfo)
+ if(data.rotation2 < -1.0f || data.rotation2 > 1.0f)
{
- sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u) with not existed gameobject entry %u, skipped.",guid,data.id );
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation2 (%f) value, skip",guid,data.id,data.rotation2 );
continue;
}
- if (gameEvent==0) // if not this is to be managed by GameEvent System
+ if(data.rotation3 < -1.0f || data.rotation3 > 1.0f)
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation3 (%f) value, skip",guid,data.id,data.rotation3 );
+ continue;
+ }
+
+ if(!MapManager::IsValidMapCoord(data.mapid,data.posX,data.posY,data.posZ,data.orientation))
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid coordinates, skip",guid,data.id );
+ continue;
+ }
+
+ if(data.phaseMask==0)
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.",guid,data.id );
+ data.phaseMask = 1;
+ }
+
+ if (gameEvent==0 && PoolId==0) // if not this is to be managed by GameEvent System or Pool system
AddGameobjectToGrid(guid, &data);
++count;
@@ -1140,7 +1297,7 @@ void ObjectMgr::LoadGameobjects()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u gameobjects", mGameObjectDataMap.size());
+ sLog.outString( ">> Loaded %lu gameobjects", (unsigned long)mGameObjectDataMap.size());
}
void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data)
@@ -1210,7 +1367,7 @@ void ObjectMgr::LoadCreatureRespawnTimes()
delete result;
- sLog.outString( ">> Loaded %u creature respawn times", mCreatureRespawnTimes.size() );
+ sLog.outString( ">> Loaded %lu creature respawn times", (unsigned long)mCreatureRespawnTimes.size() );
sLog.outString();
}
@@ -1252,7 +1409,7 @@ void ObjectMgr::LoadGameobjectRespawnTimes()
delete result;
- sLog.outString( ">> Loaded %u gameobject respawn times", mGORespawnTimes.size() );
+ sLog.outString( ">> Loaded %lu gameobject respawn times", (unsigned long)mGORespawnTimes.size() );
sLog.outString();
}
@@ -1355,7 +1512,7 @@ void ObjectMgr::LoadItemLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 Item locale strings. DB table `locales_item` is empty.");
return;
}
@@ -1404,13 +1561,13 @@ void ObjectMgr::LoadItemLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u Item locale strings", mItemLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu Item locale strings", (unsigned long)mItemLocaleMap.size() );
}
struct SQLItemLoader : public SQLStorageLoaderBase<SQLItemLoader>
{
template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
+ void convert_from_str(uint32 /*field_pos*/, char *src, D &dst)
{
dst = D(objmgr.GetScriptId(src));
}
@@ -1439,6 +1596,32 @@ void ObjectMgr::LoadItemPrototypes()
if(dbcitem)
{
+ if(proto->Class != dbcitem->Class)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct class %u, must be %u (still using DB value).",i,proto->Class,dbcitem->Class);
+ // It safe let use Class from DB
+ }
+ /* disabled: have some strange wrong cases for Subclass values.
+ for enable also uncomment Subclass field in ItemEntry structure and in Itemfmt[]
+ if(proto->SubClass != dbcitem->SubClass)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct (Class: %u, Sub: %u) pair, must be (Class: %u, Sub: %u) (still using DB value).",i,proto->Class,proto->SubClass,dbcitem->Class,dbcitem->SubClass);
+ // It safe let use Subclass from DB
+ }
+ */
+
+ if(proto->Unk0 != dbcitem->Unk0)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct %i Unk0, must be %i (still using DB value).",i,proto->Unk0,dbcitem->Unk0);
+ // It safe let use Unk0 from DB
+ }
+
+ if(proto->Material != dbcitem->Material)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct %i material, must be %i (still using DB value).",i,proto->Material,dbcitem->Material);
+ // It safe let use Material from DB
+ }
+
if(proto->InventoryType != dbcitem->InventoryType)
{
sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType);
@@ -1464,7 +1647,7 @@ void ObjectMgr::LoadItemPrototypes()
if(proto->Class >= MAX_ITEM_CLASS)
{
sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class);
- const_cast<ItemPrototype*>(proto)->Class = ITEM_CLASS_JUNK;
+ const_cast<ItemPrototype*>(proto)->Class = ITEM_CLASS_MISC;
}
if(proto->SubClass >= MaxItemSubclassValues[proto->Class])
@@ -1497,14 +1680,30 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->RequiredSkill = 0;
}
- if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE))
{
- sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped.",i,proto->AllowableClass);
- }
- if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE))
- {
- sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped.",i,proto->AllowableRace);
+ // can be used in equip slot, as page read use in inventory, or spell casting at use
+ bool req = proto->InventoryType!=INVTYPE_NON_EQUIP || proto->PageText;
+ if(!req)
+ {
+ for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j)
+ {
+ if(proto->Spells[j].SpellId)
+ {
+ req = true;
+ break;
+ }
+ }
+ }
+
+ if(req)
+ {
+ if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE))
+ sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped or use.",i,proto->AllowableClass);
+
+ if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE))
+ sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped or use.",i,proto->AllowableRace);
+ }
}
if(proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell))
@@ -1530,18 +1729,35 @@ void ObjectMgr::LoadItemPrototypes()
else if(proto->RequiredReputationRank > MIN_REPUTATION_RANK)
sLog.outErrorDb("Item (Entry: %u) has RequiredReputationFaction ==0 but RequiredReputationRank > 0, rank setting is useless.",i);
+ if(proto->MaxCount < -1)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large negative in maxcount (%i), replace by value (-1) no storing limits.",i,proto->MaxCount);
+ const_cast<ItemPrototype*>(proto)->MaxCount = -1;
+ }
+
if(proto->Stackable==0)
{
- sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%u), replace by default 1.",i,proto->Stackable);
+ sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%i), replace by default 1.",i,proto->Stackable);
const_cast<ItemPrototype*>(proto)->Stackable = 1;
}
+ else if(proto->Stackable < -1)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large negative in stackable (%i), replace by value (-1) no stacking limits.",i,proto->Stackable);
+ const_cast<ItemPrototype*>(proto)->Stackable = -1;
+ }
else if(proto->Stackable > 255)
{
sLog.outErrorDb("Item (Entry: %u) has too large value in stackable (%u), replace by hardcoded upper limit (255).",i,proto->Stackable);
const_cast<ItemPrototype*>(proto)->Stackable = 255;
}
- for (int j = 0; j < 10; j++)
+ if(proto->StatsCount > MAX_ITEM_PROTO_STATS)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS);
+ const_cast<ItemPrototype*>(proto)->StatsCount = MAX_ITEM_PROTO_STATS;
+ }
+
+ for (int j = 0; j < MAX_ITEM_PROTO_STATS; ++j)
{
// for ItemStatValue != 0
if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD)
@@ -1551,7 +1767,7 @@ void ObjectMgr::LoadItemPrototypes()
}
}
- for (int j = 0; j < 5; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_DAMAGES; ++j)
{
if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL)
{
@@ -1561,7 +1777,7 @@ void ObjectMgr::LoadItemPrototypes()
}
// special format
- if(proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN)
+ if((proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN) || (proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN_PET))
{
// spell_1
if(proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
@@ -1598,7 +1814,7 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
}
// allowed only in special format
- else if(proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN)
+ else if((proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN) || (proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN_PET))
{
sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId);
const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
@@ -1608,7 +1824,7 @@ void ObjectMgr::LoadItemPrototypes()
}
// spell_3*,spell_4*,spell_5* is empty
- for (int j = 2; j < 5; j++)
+ for (int j = 2; j < MAX_ITEM_PROTO_SPELLS; ++j)
{
if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
{
@@ -1626,7 +1842,7 @@ void ObjectMgr::LoadItemPrototypes()
// normal spell list
else
{
- for (int j = 0; j < 5; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j)
{
if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
{
@@ -1644,7 +1860,7 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
}
// allowed only in special format
- else if(proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN)
+ else if((proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN) || (proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN_PET))
{
sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
@@ -1692,10 +1908,39 @@ void ObjectMgr::LoadItemPrototypes()
if(proto->Map && !sMapStore.LookupEntry(proto->Map))
sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map);
+ if(proto->BagFamily)
+ {
+ // check bits
+ for(uint32 j = 0; j < sizeof(proto->BagFamily)*8; ++j)
+ {
+ uint32 mask = 1 << j;
+ if((proto->BagFamily & mask)==0)
+ continue;
+
+ ItemBagFamilyEntry const* bf = sItemBagFamilyStore.LookupEntry(j+1);
+ if(!bf)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has bag family bit set not listed in ItemBagFamily.dbc, remove bit",i);
+ const_cast<ItemPrototype*>(proto)->BagFamily &= ~mask;
+ continue;
+ }
+
+ if(BAG_FAMILY_MASK_CURRENCY_TOKENS & mask)
+ {
+ CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(proto->ItemId);
+ if(!ctEntry)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has currency bag family bit set in BagFamily but not listed in CurrencyTypes.dbc, remove bit",i);
+ const_cast<ItemPrototype*>(proto)->BagFamily &= ~mask;
+ }
+ }
+ }
+ }
+
if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory))
sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory);
- for (int j = 0; j < 3; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_SOCKETS; j++)
{
if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color)
{
@@ -1712,10 +1957,13 @@ void ObjectMgr::LoadItemPrototypes()
sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType);
const_cast<ItemPrototype*>(proto)->FoodType = 0;
}
- }
- // this DBC used currently only for check item templates in DB.
- sItemStore.Clear();
+ if(proto->ItemLimitCategory && !sItemLimitCategoryStore.LookupEntry(proto->ItemLimitCategory))
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong LimitCategory value (%u)",i,proto->ItemLimitCategory);
+ const_cast<ItemPrototype*>(proto)->ItemLimitCategory = 0;
+ }
+ }
}
void ObjectMgr::LoadPetLevelInfo()
@@ -1756,7 +2004,10 @@ void ObjectMgr::LoadPetLevelInfo()
if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
sLog.outErrorDb("Wrong (> %u) level %u in `pet_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level);
else
+ {
sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `pet_levelstats` table, ignoring.",current_level);
+ ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
+ }
continue;
}
else if(current_level < 1)
@@ -1999,7 +2250,7 @@ void ObjectMgr::LoadPlayerInfo()
if(sWorld.getConfig(CONFIG_START_ALL_SPELLS))
result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell_custom");
else
- result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell");
+ result = WorldDatabase.Query("SELECT race, class, Spell FROM playercreateinfo_spell");
uint32 count = 0;
@@ -2034,7 +2285,7 @@ void ObjectMgr::LoadPlayerInfo()
}
PlayerInfo* pInfo = &playerInfo[current_race][current_class];
- pInfo->spell.push_back(CreateSpellPair(fields[2].GetUInt16(), fields[3].GetUInt8()));
+ pInfo->spell.push_back(fields[2].GetUInt32());
bar.step();
++count;
@@ -2139,7 +2390,10 @@ void ObjectMgr::LoadPlayerInfo()
if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
sLog.outErrorDb("Wrong (> %u) level %u in `player_classlevelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level);
else
+ {
sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level);
+ ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
+ }
continue;
}
@@ -2234,7 +2488,10 @@ void ObjectMgr::LoadPlayerInfo()
if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
sLog.outErrorDb("Wrong (> %u) level %u in `player_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level);
else
+ {
sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_levelstats` table, ignoring.",current_level);
+ ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
+ }
continue;
}
@@ -2306,6 +2563,70 @@ void ObjectMgr::LoadPlayerInfo()
}
}
}
+
+ // Loading xp per level data
+ {
+ mPlayerXPperLevel.resize(sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
+ for (uint32 level = 0; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
+ mPlayerXPperLevel[level] = 0;
+
+ // 0 1
+ QueryResult *result = WorldDatabase.Query("SELECT lvl, xp_for_next_level FROM player_xp_for_level");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u xp for level definitions", count );
+ sLog.outErrorDb( "Error loading `player_xp_for_level` table or empty table.");
+ exit(1);
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 current_level = fields[0].GetUInt32();
+ uint32 current_xp = fields[1].GetUInt32();
+
+ if(current_level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
+ sLog.outErrorDb("Wrong (> %u) level %u in `player_xp_for_level` table, ignoring.", STRONG_MAX_LEVEL,current_level);
+ else
+ {
+ sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_xp_for_levels` table, ignoring.",current_level);
+ ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
+ }
+ continue;
+ }
+ //PlayerXPperLevel
+ mPlayerXPperLevel[current_level] = current_xp;
+ bar.step();
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u xp for level definitions", count );
+ }
+
+ // fill level gaps
+ for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
+ {
+ if( mPlayerXPperLevel[level] == 0)
+ {
+ sLog.outErrorDb("Level %i does not have XP for level data. Using data of level [%i] + 100.",level+1, level);
+ mPlayerXPperLevel[level] = mPlayerXPperLevel[level-1]+100;
+ }
+ }
}
void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const
@@ -2550,15 +2871,15 @@ void ObjectMgr::LoadGroups()
result = CharacterDatabase.Query("SELECT memberGuid, assistant, subgroup, leaderGuid FROM group_member ORDER BY leaderGuid");
if(!result)
{
- barGoLink bar( 1 );
- bar.step();
+ barGoLink bar2( 1 );
+ bar2.step();
}
else
{
- barGoLink bar( result->GetRowCount() );
+ barGoLink bar2( result->GetRowCount() );
do
{
- bar.step();
+ bar2.step();
Field *fields = result->Fetch();
count++;
leaderGuid = MAKE_NEW_GUID(fields[3].GetUInt32(), 0, HIGHGUID_PLAYER);
@@ -2610,15 +2931,15 @@ void ObjectMgr::LoadGroups()
if(!result)
{
- barGoLink bar( 1 );
- bar.step();
+ barGoLink bar2( 1 );
+ bar2.step();
}
else
{
- barGoLink bar( result->GetRowCount() );
+ barGoLink bar2( result->GetRowCount() );
do
{
- bar.step();
+ bar2.step();
Field *fields = result->Fetch();
count++;
leaderGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
@@ -2632,7 +2953,14 @@ void ObjectMgr::LoadGroups()
}
}
- InstanceSave *save = sInstanceSaveManager.AddInstanceSave(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
+ MapEntry const* mapEntry = sMapStore.LookupEntry(fields[1].GetUInt32());
+ if(!mapEntry || !mapEntry->IsDungeon())
+ {
+ sLog.outErrorDb("Incorrect entry in group_instance table : no dungeon map %d", fields[1].GetUInt32());
+ continue;
+ }
+
+ InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapEntry->MapID, fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
group->BindToInstance(save, fields[3].GetBool(), true);
}while( result->NextRow() );
delete result;
@@ -2658,31 +2986,31 @@ void ObjectMgr::LoadQuests()
QueryResult *result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, SkillOrClass, MinLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue,"
// 9 10 11 12 13 14 15 16
"RepObjectiveFaction, RepObjectiveValue, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime,"
- // 17 18 19 20 21 22 23 24 25 26
- "QuestFlags, SpecialFlags, CharTitleId, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell,"
- // 27 28 29 30 31 32 33 34 35 36
+ // 17 18 19 20 21 22 23 24 25 26 27 28
+ "QuestFlags, SpecialFlags, CharTitleId, PlayersSlain, BonusTalents, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell,"
+ // 29 30 31 32 33 34 35 36 37 38
"Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4,"
- // 37 38 39 40 41 42 43 44
+ // 39 40 41 42 43 44 45 46
"ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4,"
- // 45 46 47 48 49 50 51 52 53 54 54 55
- "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4, ReqSourceRef1, ReqSourceRef2, ReqSourceRef3, ReqSourceRef4,"
- // 57 58 59 60 61 62 63 64
+ // 47 48 49 50 51 52 53 54
+ "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4,"
+ // 55 56 57 58 59 60 61 62
"ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4,"
- // 65 66 67 68
+ // 63 64 65 66
"ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4,"
- // 69 70 71 72 73 74
+ // 67 68 69 70 71 72
"RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6,"
- // 75 76 77 78 79 80
+ // 73 74 75 76 77 78
"RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6,"
- // 81 82 83 84 85 86 87 88
+ // 79 80 81 82 83 84 85 86
"RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4,"
- // 89 90 91 92 93 94 95 96 97 98
+ // 87 88 89 90 91 92 93 94 95 96
"RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5,"
- // 99 100 101 102 103 104 105 106 107 108 109
+ // 97 98 99 100 101 102 103 104 105 106 107
"RewHonorableKills, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt,"
- // 110 111 112 113 114 115 116 117 118 119
- "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
- // 120 121
+ // 108 109 110 111 112 113 114 115 116 117
+ "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
+ // 118 119
"StartScript, CompleteScript"
" FROM quest_template");
if(result == NULL)
@@ -2854,10 +3182,10 @@ void ObjectMgr::LoadQuests()
// no changes, quest can't be done for this requirement
}
- if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > Player::Reputation_Cap)
+ if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > ReputationMgr::Reputation_Cap)
{
sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RequiredMinRepValue,Player::Reputation_Cap);
+ qinfo->GetQuestId(),qinfo->RequiredMinRepValue,ReputationMgr::Reputation_Cap);
// no changes, quest can't be done for this requirement
}
@@ -2976,20 +3304,6 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(),j+1,id,id);
// no changes, quest can't be done for this requirement
}
-
- if(!qinfo->ReqSourceCount[j])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
-
- if(!qinfo->ReqSourceRef[j])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
}
else
{
@@ -2999,41 +3313,6 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]);
// no changes, quest ignore this data
}
-
- if(qinfo->ReqSourceRef[j]>0)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]);
- // no changes, quest ignore this data
- }
- }
- }
-
- for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
- {
- uint32 ref = qinfo->ReqSourceRef[j];
- if(ref)
- {
- if(ref > QUEST_OBJECTIVES_COUNT)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.",
- qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT);
- // no changes, quest can't be done for this requirement
- }
- else
- if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,ref,ref,ref);
- // no changes, quest can't be done for this requirement
- }
- else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1])
- {
- sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.",
- qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]);
- // no changes, quest can't be done for this requirement
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
}
}
@@ -3047,7 +3326,7 @@ void ObjectMgr::LoadQuests()
{
sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.",
qinfo->GetQuestId(),j+1,id,id);
- // no changes, quest can't be done for this requirement
+ continue;
}
if(!qinfo->ReqCreatureOrGOId[j])
@@ -3254,14 +3533,15 @@ void ObjectMgr::LoadQuests()
if(qinfo->NextQuestInChain)
{
- if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end())
+ QuestMap::iterator qNextItr = mQuestTemplates.find(qinfo->NextQuestInChain);
+ if(qNextItr == mQuestTemplates.end())
{
sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.",
qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain );
qinfo->NextQuestInChain = 0;
}
else
- mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId());
+ qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId());
}
// fill additional data stores
@@ -3279,14 +3559,15 @@ void ObjectMgr::LoadQuests()
if(qinfo->NextQuestId)
{
- if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end())
+ QuestMap::iterator qNextItr = mQuestTemplates.find(abs(qinfo->GetNextQuestId()));
+ if (qNextItr == mQuestTemplates.end())
{
sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
}
else
{
int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
- mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId);
+ qNextItr->second->prevQuests.push_back(signedQuestId);
}
}
@@ -3327,7 +3608,7 @@ void ObjectMgr::LoadQuests()
}
sLog.outString();
- sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() );
+ sLog.outString( ">> Loaded %lu quests definitions", (unsigned long)mQuestTemplates.size() );
}
void ObjectMgr::LoadQuestLocales()
@@ -3352,7 +3633,7 @@ void ObjectMgr::LoadQuestLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty.");
return;
}
@@ -3463,7 +3744,7 @@ void ObjectMgr::LoadQuestLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu Quest locale strings", (unsigned long)mQuestLocaleMap.size() );
}
void ObjectMgr::LoadPetCreateSpells()
@@ -3493,20 +3774,53 @@ void ObjectMgr::LoadPetCreateSpells()
uint32 creature_id = fields[0].GetUInt32();
- if(!creature_id || !sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
+ if(!creature_id)
+ {
+ sLog.outErrorDb("Creature id %u listed in `petcreateinfo_spell` not exist.",creature_id);
continue;
+ }
+
+ CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(creature_id);
+ if(!cInfo)
+ {
+ sLog.outErrorDb("Creature id %u listed in `petcreateinfo_spell` not exist.",creature_id);
+ continue;
+ }
PetCreateSpellEntry PetCreateSpell;
+
+ bool have_spell = false;
+ bool have_spell_db = false;
for(int i = 0; i < 4; i++)
{
PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32();
- if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i]))
+ if(!PetCreateSpell.spellid[i])
+ continue;
+
+ have_spell_db = true;
+
+ SpellEntry const* i_spell = sSpellStore.LookupEntry(PetCreateSpell.spellid[i]);
+ if(!i_spell)
+ {
sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]);
+ PetCreateSpell.spellid[i] = 0;
+ continue;
+ }
+
+ have_spell = true;
}
- mPetCreateSpell[creature_id] = PetCreateSpell;
+ if(!have_spell_db)
+ {
+ sLog.outErrorDb("Creature %u listed in `petcreateinfo_spell` have only 0 spell data, why it listed?",creature_id);
+ continue;
+ }
+ if(!have_spell)
+ continue;
+
+ mPetCreateSpell[creature_id] = PetCreateSpell;
++count;
}
while (result->NextRow());
@@ -3584,6 +3898,16 @@ void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
break;
}
+ case SCRIPT_COMMAND_EMOTE:
+ {
+ if(!sEmotesStore.LookupEntry(tmp.datalong))
+ {
+ sLog.outErrorDb("Table `%s` has invalid emote id (datalong = %u) in SCRIPT_COMMAND_EMOTE for script id %u",tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+ break;
+ }
+
case SCRIPT_COMMAND_TELEPORT_TO:
{
if(!sMapStore.LookupEntry(tmp.datalong))
@@ -3712,6 +4036,21 @@ void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
}
case SCRIPT_COMMAND_REMOVE_AURA:
+ {
+ if(!sSpellStore.LookupEntry(tmp.datalong))
+ {
+ 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);
+ continue;
+ }
+ if(tmp.datalong2 & ~0x1) // 1 bits (0,1)
+ {
+ sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u",
+ tablename,tmp.datalong2,tmp.id);
+ continue;
+ }
+ break;
+ }
case SCRIPT_COMMAND_CAST_SPELL:
{
if(!sSpellStore.LookupEntry(tmp.datalong))
@@ -3720,6 +4059,12 @@ void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
tablename,tmp.datalong,tmp.id);
continue;
}
+ if(tmp.datalong2 & ~0x3) // 2 bits
+ {
+ sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u",
+ tablename,tmp.datalong2,tmp.id);
+ continue;
+ }
break;
}
}
@@ -3968,7 +4313,7 @@ void ObjectMgr::LoadPageTextLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty.");
return;
}
@@ -4005,13 +4350,13 @@ void ObjectMgr::LoadPageTextLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu PageText locale strings", (unsigned long)mPageTextLocaleMap.size() );
}
struct SQLInstanceLoader : public SQLStorageLoaderBase<SQLInstanceLoader>
{
template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
+ void convert_from_str(uint32 /*field_pos*/, char *src, D &dst)
{
dst = D(objmgr.GetScriptId(src));
}
@@ -4035,14 +4380,20 @@ void ObjectMgr::LoadInstanceTemplate()
else if(!entry->HasResetTime())
continue;
+ //FIXME: now exist heroic instance, normal/heroic raid instances
+ // entry->resetTimeHeroic store reset time for both heroic mode instance (raid and non-raid)
+ // entry->resetTimeRaid store reset time for normal raid only
+ // for current state entry->resetTimeRaid == entry->resetTimeHeroic in case raid instances with heroic mode.
+ // but at some point wee need implement reset time dependent from raid instance mode
if(temp->reset_delay == 0)
{
// use defaults from the DBC
- if(entry->SupportsHeroicMode())
+ if(entry->resetTimeHeroic) // for both raid and non raids, read above
{
temp->reset_delay = entry->resetTimeHeroic / DAY;
}
else if (entry->resetTimeRaid && entry->map_type == MAP_RAID)
+ // for normal raid only
{
temp->reset_delay = entry->resetTimeRaid / DAY;
}
@@ -4056,27 +4407,16 @@ void ObjectMgr::LoadInstanceTemplate()
sLog.outString();
}
-void ObjectMgr::AddGossipText(GossipText *pGText)
+GossipText const *ObjectMgr::GetGossipText(uint32 Text_ID) const
{
- ASSERT( pGText->Text_ID );
- ASSERT( mGossipText.find(pGText->Text_ID) == mGossipText.end() );
- mGossipText[pGText->Text_ID] = pGText;
-}
-
-GossipText *ObjectMgr::GetGossipText(uint32 Text_ID)
-{
- GossipTextMap::const_iterator itr;
- for (itr = mGossipText.begin(); itr != mGossipText.end(); ++itr)
- {
- if(itr->second->Text_ID == Text_ID)
- return itr->second;
- }
+ GossipTextMap::const_iterator itr = mGossipText.find(Text_ID);
+ if(itr != mGossipText.end())
+ return &itr->second;
return NULL;
}
void ObjectMgr::LoadGossipText()
{
- GossipText *pGText;
QueryResult *result = WorldDatabase.Query( "SELECT * FROM npc_text" );
int count = 0;
@@ -4103,34 +4443,29 @@ void ObjectMgr::LoadGossipText()
bar.step();
- pGText = new GossipText;
- pGText->Text_ID = fields[cic++].GetUInt32();
-
- for (int i=0; i< 8; i++)
+ uint32 Text_ID = fields[cic++].GetUInt32();
+ if(!Text_ID)
{
- pGText->Options[i].Text_0 = fields[cic++].GetCppString();
- pGText->Options[i].Text_1 = fields[cic++].GetCppString();
-
- pGText->Options[i].Language = fields[cic++].GetUInt32();
- pGText->Options[i].Probability = fields[cic++].GetFloat();
+ sLog.outErrorDb("Table `npc_text` has record wit reserved id 0, ignore.");
+ continue;
+ }
- pGText->Options[i].Emotes[0]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[0]._Emote = fields[cic++].GetUInt32();
+ GossipText& gText = mGossipText[Text_ID];
- pGText->Options[i].Emotes[1]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[1]._Emote = fields[cic++].GetUInt32();
+ for (int i=0; i< 8; i++)
+ {
+ gText.Options[i].Text_0 = fields[cic++].GetCppString();
+ gText.Options[i].Text_1 = fields[cic++].GetCppString();
- pGText->Options[i].Emotes[2]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[2]._Emote = fields[cic++].GetUInt32();
- }
+ gText.Options[i].Language = fields[cic++].GetUInt32();
+ gText.Options[i].Probability = fields[cic++].GetFloat();
- if ( !pGText->Text_ID ){
- delete pGText;
- continue;
+ for(int j=0; j < 3; ++j)
+ {
+ gText.Options[i].Emotes[j]._Delay = fields[cic++].GetUInt32();
+ gText.Options[i].Emotes[j]._Emote = fields[cic++].GetUInt32();
+ }
}
-
- AddGossipText( pGText );
-
} while( result->NextRow() );
sLog.outString();
@@ -4159,8 +4494,8 @@ void ObjectMgr::LoadNpcTextLocales()
bar.step();
- sLog.outString("");
- sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty.");
+ sLog.outString();
+ sLog.outString(">> Loaded 0 NpcText locale strings. DB table `locales_npc_text` is empty.");
return;
}
@@ -4210,7 +4545,7 @@ void ObjectMgr::LoadNpcTextLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu NpcText locale strings", (unsigned long)mNpcTextLocaleMap.size() );
}
//not very fast function but it is called only once a day, or on starting-up
@@ -4224,14 +4559,27 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
// 0 1 2 3 4 5 6 7 8 9
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);
if ( !result )
+ {
+ barGoLink bar(1);
+ bar.step();
+ sLog.outString();
+ sLog.outString(">> Only expired mails (need to be return or delete) or DB table `mail` is empty.");
return; // any mails need to be returned or deleted
- Field *fields;
+ }
+
//std::ostringstream delitems, delmails; //will be here for optimization
//bool deletemail = false, deleteitem = false;
//delitems << "DELETE FROM item_instance WHERE guid IN ( ";
//delmails << "DELETE FROM mail WHERE id IN ( "
+
+ barGoLink bar( result->GetRowCount() );
+ uint32 count = 0;
+ Field *fields;
+
do
{
+ bar.step();
+
fields = result->Fetch();
Mail *m = new Mail;
m->messageID = fields[0].GetUInt32();
@@ -4297,8 +4645,12 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
//delmails << m->messageID << ", ";
CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID);
delete m;
+ ++count;
} while (result->NextRow());
delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u mails", count );
}
void ObjectMgr::LoadQuestAreaTriggers()
@@ -4455,7 +4807,7 @@ void ObjectMgr::LoadAreaTriggerScripts()
sLog.outString( ">> Loaded %u areatrigger scripts", count );
}
-uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
+uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid, uint32 team )
{
bool found = false;
float dist;
@@ -4464,24 +4816,31 @@ uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
{
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
- if(node && node->map_id == mapid)
+ if(!node || node->map_id != mapid || !node->MountCreatureID[team == ALLIANCE ? 1 : 0])
+ continue;
+
+ uint8 field = (uint8)((i - 1) / 32);
+ uint32 submask = 1<<((i-1)%32);
+
+ // skip not taxi network nodes
+ if((sTaxiNodesMask[field] & submask)==0)
+ continue;
+
+ float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z);
+ if(found)
{
- float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z);
- if(found)
+ if(dist2 < dist)
{
- if(dist2 < dist)
- {
- dist = dist2;
- id = i;
- }
- }
- else
- {
- found = true;
dist = dist2;
id = i;
}
}
+ else
+ {
+ found = true;
+ dist = dist2;
+ id = i;
+ }
}
return id;
@@ -4511,7 +4870,7 @@ void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, ui
path = dest_i->second.ID;
}
-uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
+uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team, bool allowed_alt_team /* = false */)
{
uint16 mount_entry = 0;
uint16 mount_id = 0;
@@ -4519,17 +4878,26 @@ uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id);
if(node)
{
- if (team == ALLIANCE) mount_entry = node->alliance_mount_type;
- else mount_entry = node->horde_mount_type;
+ if (team == ALLIANCE)
+ {
+ mount_entry = node->MountCreatureID[1];
+ if(!mount_entry && allowed_alt_team)
+ mount_entry = node->MountCreatureID[0];
- CreatureInfo const *cinfo = GetCreatureTemplate(mount_entry);
- if (cinfo)
+ CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
+ if(ci)
+ mount_id = ci->Modelid_A1;
+ }
+ if (team == HORDE)
{
- if(! (mount_id = cinfo->GetRandomValidModelId()))
- {
- sLog.outErrorDb("No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry);
- return false;
- }
+ mount_entry = node->MountCreatureID[0];
+
+ if(!mount_entry && allowed_alt_team)
+ mount_entry = node->MountCreatureID[1];
+
+ CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
+ if(ci)
+ mount_id = ci->Modelid_H1;
}
}
@@ -4657,7 +5025,7 @@ void ObjectMgr::LoadGraveyardZones()
WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team)
{
// search for zone associated closest graveyard
- uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y);
+ uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y,z);
// Simulate std. algorithm:
// found some graveyard associated to (ghost_zone,ghost_map)
@@ -4668,7 +5036,10 @@ WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float
// then check faction
GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId);
GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId);
- if(graveLow==graveUp)
+ MapEntry const* map = sMapStore.LookupEntry(MapId);
+ // not need to check validity of map object; MapId _MUST_ be valid here
+
+ if(graveLow==graveUp && !map->IsBattleArena())
{
sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
return NULL;
@@ -4709,8 +5080,10 @@ WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float
if(MapId != entry->map_id)
{
// if find graveyard at different map from where entrance placed (or no entrance data), use any first
- if (!mapEntry || mapEntry->entrance_map < 0 || mapEntry->entrance_map != entry->map_id ||
- mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0)
+ if (!mapEntry ||
+ mapEntry->entrance_map < 0 ||
+ mapEntry->entrance_map != entry->map_id ||
+ (mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0))
{
// not have any corrdinates for check distance anyway
entryFar = entry;
@@ -4855,7 +5228,7 @@ void ObjectMgr::LoadAreaTriggerTeleports()
uint32 count = 0;
- // 0 1 2 3 4 5 6
+ // 0 1 2 3 4 5 6
QueryResult *result = WorldDatabase.Query("SELECT id, access_id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
if( !result )
{
@@ -4896,7 +5269,7 @@ void ObjectMgr::LoadAreaTriggerTeleports()
sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
continue;
}
-
+
MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId);
if(!mapEntry)
{
@@ -5007,7 +5380,8 @@ void ObjectMgr::LoadAccessRequirements()
if(ar.heroicQuest)
{
- if(!GetQuestTemplate(ar.heroicQuest))
+ QuestMap::iterator qReqItr = mQuestTemplates.find(ar.heroicQuest);
+ if(qReqItr == mQuestTemplates.end())
{
sLog.outErrorDb("Required Heroic Quest %u not exist for trigger %u, remove heroic quest done requirement.",ar.heroicQuest,requiremt_ID);
ar.heroicQuest = 0;
@@ -5016,7 +5390,8 @@ void ObjectMgr::LoadAccessRequirements()
if(ar.quest)
{
- if(!GetQuestTemplate(ar.quest))
+ QuestMap::iterator qReqItr = mQuestTemplates.find(ar.quest);
+ if(qReqItr == mQuestTemplates.end())
{
sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",ar.quest,requiremt_ID);
ar.quest = 0;
@@ -5033,6 +5408,9 @@ void ObjectMgr::LoadAccessRequirements()
sLog.outString( ">> Loaded %u access requirement definitions", count );
}
+/*
+ * Searches for the areatrigger which teleports players out of the given map
+ */
AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const
{
const MapEntry *mapEntry = sMapStore.LookupEntry(Map);
@@ -5049,6 +5427,23 @@ AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const
return NULL;
}
+/**
+ * Searches for the areatrigger which teleports players to the given map
+ */
+AreaTrigger const* ObjectMgr::GetMapEntranceTrigger(uint32 Map) const
+{
+ for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); ++itr)
+ {
+ if(itr->second.target_mapId == Map)
+ {
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first);
+ if(atEntry)
+ return &itr->second;
+ }
+ }
+ return NULL;
+}
+
void ObjectMgr::SetHighestGuids()
{
QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" );
@@ -5065,9 +5460,6 @@ void ObjectMgr::SetHighestGuids()
delete result;
}
- // pet guids are not saved to DB, set to 0 (pet guid != pet id)
- m_hiPetGuid = 0;
-
result = CharacterDatabase.Query( "SELECT MAX(guid) FROM item_instance" );
if( result )
{
@@ -5141,24 +5533,24 @@ uint32 ObjectMgr::GenerateArenaTeamId()
return m_arenaTeamId++;
}
-uint32 ObjectMgr::GenerateGuildId()
+uint32 ObjectMgr::GenerateAuctionID()
{
- if(m_guildId>=0xFFFFFFFE)
+ if(m_auctionid>=0xFFFFFFFE)
{
- sLog.outError("Guild ids overflow!! Can't continue, shutting down server. ");
+ sLog.outError("Auctions ids overflow!! Can't continue, shutting down server. ");
World::StopNow(ERROR_EXIT_CODE);
}
- return m_guildId++;
+ return m_auctionid++;
}
-uint32 ObjectMgr::GenerateAuctionID()
+uint32 ObjectMgr::GenerateGuildId()
{
- if(m_auctionid>=0xFFFFFFFE)
+ if(m_guildId>=0xFFFFFFFE)
{
- sLog.outError("Auctions ids overflow!! Can't continue, shutting down server. ");
+ sLog.outError("Guild ids overflow!! Can't continue, shutting down server. ");
World::StopNow(ERROR_EXIT_CODE);
}
- return m_auctionid++;
+ return m_guildId++;
}
uint32 ObjectMgr::GenerateMailID()
@@ -5220,6 +5612,13 @@ uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh)
World::StopNow(ERROR_EXIT_CODE);
}
return m_hiPetGuid++;
+ case HIGHGUID_VEHICLE:
+ if(m_hiVehicleGuid>=0x00FFFFFF)
+ {
+ sLog.outError("Vehicle guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiVehicleGuid++;
case HIGHGUID_PLAYER:
if(m_hiCharGuid>=0xFFFFFFFE)
{
@@ -5271,7 +5670,7 @@ void ObjectMgr::LoadGameObjectLocales()
bar.step();
- sLog.outString("");
+ sLog.outString();
sLog.outString(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty.");
return;
}
@@ -5303,9 +5702,9 @@ void ObjectMgr::LoadGameObjectLocales()
}
}
- for(int i = MAX_LOCALE; i < MAX_LOCALE*2-1; ++i)
+ for(int i = 1; i < MAX_LOCALE; ++i)
{
- std::string str = fields[i].GetCppString();
+ std::string str = fields[i+(MAX_LOCALE-1)].GetCppString();
if(!str.empty())
{
int idx = GetOrNewIndexForLocale(LocaleConstant(i));
@@ -5324,18 +5723,73 @@ void ObjectMgr::LoadGameObjectLocales()
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() );
+ sLog.outString( ">> Loaded %lu gameobject locale strings", (unsigned long)mGameObjectLocaleMap.size() );
}
struct SQLGameObjectLoader : public SQLStorageLoaderBase<SQLGameObjectLoader>
{
template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
+ void convert_from_str(uint32 /*field_pos*/, char *src, D &dst)
{
dst = D(objmgr.GetScriptId(src));
}
};
+inline void CheckGOLockId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ if (sLockStore.LookupEntry(dataN))
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but lock (Id: %u) not found.",
+ goInfo->id,goInfo->type,N,goInfo->door.lockId,goInfo->door.lockId);
+}
+
+inline void CheckGOLinkedTrapId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ if (GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(dataN))
+ {
+ if (trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
+ goInfo->id,goInfo->type,N,dataN,dataN,GAMEOBJECT_TYPE_TRAP);
+ }
+ /* disable check for while (too many error reports baout not existed in trap templates
+ else
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
+ goInfo->id,goInfo->type,N,dataN,dataN);
+ */
+}
+
+inline void CheckGOSpellId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ if (sSpellStore.LookupEntry(dataN))
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but Spell (Entry %u) not exist.",
+ goInfo->id,goInfo->type,N,dataN,dataN);
+}
+
+inline void CheckAndFixGOChairHeightId(GameObjectInfo const* goInfo,uint32 const& dataN,uint32 N)
+{
+ if (dataN <= (UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR) )
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but correct chair height in range 0..%i.",
+ goInfo->id,goInfo->type,N,dataN,UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR);
+
+ // prevent client and server unexpected work
+ const_cast<uint32&>(dataN) = 0;
+}
+
+inline void CheckGONoDamageImmuneId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N)
+{
+ // 0/1 correct values
+ if (dataN <= 1)
+ return;
+
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) noDamageImmune field value.",
+ goInfo->id,goInfo->type,N,dataN);
+}
+
void ObjectMgr::LoadGameobjectInfo()
{
SQLGameObjectLoader loader;
@@ -5345,139 +5799,104 @@ void ObjectMgr::LoadGameobjectInfo()
for(uint32 id = 1; id < sGOStorage.MaxEntry; id++)
{
GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(id);
- if(!goInfo)
+ if (!goInfo)
continue;
switch(goInfo->type)
{
case GAMEOBJECT_TYPE_DOOR: //0
{
- if(goInfo->door.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->door.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId);
- }
+ if (goInfo->door.lockId)
+ CheckGOLockId(goInfo,goInfo->door.lockId,1);
+ CheckGONoDamageImmuneId(goInfo,goInfo->door.noDamageImmune,3);
break;
}
case GAMEOBJECT_TYPE_BUTTON: //1
{
- if(goInfo->button.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->button.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId);
- }
+ if (goInfo->button.lockId)
+ CheckGOLockId(goInfo,goInfo->button.lockId,1);
+ CheckGONoDamageImmuneId(goInfo,goInfo->button.noDamageImmune,4);
+ break;
+ }
+ case GAMEOBJECT_TYPE_QUESTGIVER: //2
+ {
+ if (goInfo->questgiver.lockId)
+ CheckGOLockId(goInfo,goInfo->questgiver.lockId,0);
+ CheckGONoDamageImmuneId(goInfo,goInfo->questgiver.noDamageImmune,5);
break;
}
case GAMEOBJECT_TYPE_CHEST: //3
{
- if(goInfo->chest.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->chest.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId);
- }
- if(goInfo->chest.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->chest.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId);
- */
- }
+ if (goInfo->chest.lockId)
+ CheckGOLockId(goInfo,goInfo->chest.lockId,0);
+
+ if (goInfo->chest.linkedTrapId) // linked trap
+ CheckGOLinkedTrapId(goInfo,goInfo->chest.linkedTrapId,7);
break;
}
case GAMEOBJECT_TYPE_TRAP: //6
{
- /* disable check for while
- if(goInfo->trap.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->trap.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId);
- }
+ if (goInfo->trap.lockId)
+ CheckGOLockId(goInfo,goInfo->trap.lockId,0);
+ /* disable check for while, too many not existed spells
+ if (goInfo->trap.spellId) // spell
+ CheckGOSpellId(goInfo,goInfo->trap.spellId,3);
*/
break;
}
case GAMEOBJECT_TYPE_CHAIR: //7
- if(goInfo->chair.height > 2)
- {
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..2.",
- id,goInfo->type,goInfo->chair.height);
-
- // prevent client and server unexpected work
- const_cast<GameObjectInfo*>(goInfo)->chair.height = 0;
- }
+ CheckAndFixGOChairHeightId(goInfo,goInfo->chair.height,1);
break;
case GAMEOBJECT_TYPE_SPELL_FOCUS: //8
{
- if(goInfo->spellFocus.focusId)
+ if (goInfo->spellFocus.focusId)
{
- if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId))
+ if (!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId))
sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.",
id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId);
}
- if(goInfo->spellFocus.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->spellFocus.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId);
- */
- }
+ if (goInfo->spellFocus.linkedTrapId) // linked trap
+ CheckGOLinkedTrapId(goInfo,goInfo->spellFocus.linkedTrapId,2);
break;
}
case GAMEOBJECT_TYPE_GOOBER: //10
{
- if(goInfo->goober.pageId) // pageId
+ if (goInfo->goober.lockId)
+ CheckGOLockId(goInfo,goInfo->goober.lockId,0);
+
+ if (goInfo->goober.pageId) // pageId
{
- if(!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
+ if (!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.",
id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId);
}
- /* disable check for while
- if(goInfo->goober.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->goober.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId);
- }
+ /* disable check for while, too many not existed spells
+ if (goInfo->goober.spellId) // spell
+ CheckGOSpellId(goInfo,goInfo->goober.spellId,10);
*/
- if(goInfo->goober.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->goober.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId);
- */
- }
+ CheckGONoDamageImmuneId(goInfo,goInfo->goober.noDamageImmune,11);
+ if (goInfo->goober.linkedTrapId) // linked trap
+ CheckGOLinkedTrapId(goInfo,goInfo->goober.linkedTrapId,12);
+ break;
+ }
+ case GAMEOBJECT_TYPE_AREADAMAGE: //12
+ {
+ if (goInfo->areadamage.lockId)
+ CheckGOLockId(goInfo,goInfo->areadamage.lockId,0);
+ break;
+ }
+ case GAMEOBJECT_TYPE_CAMERA: //13
+ {
+ if (goInfo->camera.lockId)
+ CheckGOLockId(goInfo,goInfo->camera.lockId,0);
break;
}
case GAMEOBJECT_TYPE_MO_TRANSPORT: //15
{
- if(goInfo->moTransport.taxiPathId)
+ if (goInfo->moTransport.taxiPathId)
{
- if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty())
+ if (goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty())
sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId);
}
@@ -5485,26 +5904,41 @@ void ObjectMgr::LoadGameobjectInfo()
}
case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18
{
- /* disabled
- if(goInfo->summoningRitual.spellId)
- {
- if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId);
- }
+ /* disable check for while, too many not existed spells
+ // always must have spell
+ CheckGOSpellId(goInfo,goInfo->summoningRitual.spellId,1);
*/
break;
}
case GAMEOBJECT_TYPE_SPELLCASTER: //22
{
- if(goInfo->spellcaster.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId);
- }
+ // always must have spell
+ CheckGOSpellId(goInfo,goInfo->spellcaster.spellId,0);
break;
}
+ case GAMEOBJECT_TYPE_FLAGSTAND: //24
+ {
+ if (goInfo->flagstand.lockId)
+ CheckGOLockId(goInfo,goInfo->flagstand.lockId,0);
+ CheckGONoDamageImmuneId(goInfo,goInfo->flagstand.noDamageImmune,5);
+ break;
+ }
+ case GAMEOBJECT_TYPE_FISHINGHOLE: //25
+ {
+ if (goInfo->fishinghole.lockId)
+ CheckGOLockId(goInfo,goInfo->fishinghole.lockId,4);
+ break;
+ }
+ case GAMEOBJECT_TYPE_FLAGDROP: //26
+ {
+ if (goInfo->flagdrop.lockId)
+ CheckGOLockId(goInfo,goInfo->flagdrop.lockId,0);
+ CheckGONoDamageImmuneId(goInfo,goInfo->flagdrop.noDamageImmune,3);
+ break;
+ }
+ case GAMEOBJECT_TYPE_BARBER_CHAIR: //32
+ CheckAndFixGOChairHeightId(goInfo,goInfo->barberChair.chairheight,0);
+ break;
}
}
@@ -5553,6 +5987,13 @@ uint32 ObjectMgr::GetBaseXP(uint32 level)
return mBaseXPTable[level] ? mBaseXPTable[level] : 0;
}
+uint32 ObjectMgr::GetXPForLevel(uint32 level)
+{
+ if (level < mPlayerXPperLevel.size())
+ return mPlayerXPperLevel[level];
+ return 0;
+}
+
void ObjectMgr::LoadPetNames()
{
uint32 count = 0;
@@ -5754,6 +6195,128 @@ void ObjectMgr::LoadReputationOnKill()
sLog.outString(">> Loaded %u creature award reputation definitions", count);
}
+void ObjectMgr::LoadPointsOfInterest()
+{
+ uint32 count = 0;
+
+ // 0 1 2 3 4 5
+ QueryResult *result = WorldDatabase.Query("SELECT entry, x, y, icon, flags, data, icon_name FROM points_of_interest");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 Points of Interest definitions. DB table `points_of_interest` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 point_id = fields[0].GetUInt32();
+
+ PointOfInterest POI;
+ POI.x = fields[1].GetFloat();
+ POI.y = fields[2].GetFloat();
+ POI.icon = fields[3].GetUInt32();
+ POI.flags = fields[4].GetUInt32();
+ POI.data = fields[5].GetUInt32();
+ POI.icon_name = fields[6].GetCppString();
+
+ if(!MaNGOS::IsValidMapCoord(POI.x,POI.y))
+ {
+ sLog.outErrorDb("Table `points_of_interest` (Entry: %u) have invalid coordinates (X: %f Y: %f), ignored.",point_id,POI.x,POI.y);
+ continue;
+ }
+
+ mPointsOfInterest[point_id] = POI;
+
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u Points of Interest definitions", count);
+}
+
+void ObjectMgr::LoadNPCSpellClickSpells()
+{
+ uint32 count = 0;
+
+ mSpellClickInfoMap.clear();
+
+ QueryResult *result = WorldDatabase.Query("SELECT npc_entry, spell_id, quest_id, cast_flags FROM npc_spellclick_spells");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 npc_entry = fields[0].GetUInt32();
+ CreatureInfo const* cInfo = GetCreatureTemplate(npc_entry);
+ if (!cInfo)
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown creature_template %u. Skipping entry.", npc_entry);
+ continue;
+ }
+
+ uint32 spellid = fields[1].GetUInt32();
+ SpellEntry const *spellinfo = sSpellStore.LookupEntry(spellid);
+ if (!spellinfo)
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown spellid %u. Skipping entry.", spellid);
+ continue;
+ }
+
+ uint32 quest = fields[2].GetUInt32();
+
+ // quest might be 0 to enable spellclick independent of any quest
+ if (quest)
+ {
+ if(mQuestTemplates.find(quest) == mQuestTemplates.end())
+ {
+ sLog.outErrorDb("Table npc_spellclick_spells references unknown quest %u. Skipping entry.", spellid);
+ continue;
+ }
+
+ }
+
+ uint8 castFlags = fields[3].GetUInt8();
+ SpellClickInfo info;
+ info.spellId = spellid;
+ info.questId = quest;
+ info.castFlags = castFlags;
+ mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info));
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u spellclick definitions", count);
+}
+
void ObjectMgr::LoadWeatherZoneChances()
{
uint32 count = 0;
@@ -5792,19 +6355,19 @@ void ObjectMgr::LoadWeatherZoneChances()
if(wzc.data[season].rainChance > 100)
{
wzc.data[season].rainChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%",zone_id,season);
+ sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%%",zone_id,season);
}
if(wzc.data[season].snowChance > 100)
{
wzc.data[season].snowChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%",zone_id,season);
+ sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%%",zone_id,season);
}
if(wzc.data[season].stormChance > 100)
{
wzc.data[season].stormChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%",zone_id,season);
+ sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%%",zone_id,season);
}
}
@@ -6021,11 +6584,18 @@ void ObjectMgr::LoadReservedPlayersNames()
bar.step();
fields = result->Fetch();
std::string name= fields[0].GetCppString();
- if(normalizePlayerName(name))
+
+ std::wstring wstr;
+ if(!Utf8toWStr (name,wstr))
{
- m_ReservedNames.insert(name);
- ++count;
+ sLog.outError("Table `reserved_name` have invalid name: %s", name.c_str() );
+ continue;
}
+
+ wstrToLower(wstr);
+
+ m_ReservedNames.insert(wstr);
+ ++count;
} while ( result->NextRow() );
delete result;
@@ -6034,6 +6604,17 @@ void ObjectMgr::LoadReservedPlayersNames()
sLog.outString( ">> Loaded %u reserved player names", count );
}
+bool ObjectMgr::IsReservedName( const std::string& name ) const
+{
+ std::wstring wstr;
+ if(!Utf8toWStr (name,wstr))
+ return false;
+
+ wstrToLower(wstr);
+
+ return m_ReservedNames.find(wstr) != m_ReservedNames.end();
+}
+
enum LanguageType
{
LT_BASIC_LATIN = 0x0000,
@@ -6182,55 +6763,26 @@ int ObjectMgr::GetOrNewIndexForLocale( LocaleConstant loc )
return m_LocalForIndex.size()-1;
}
-void ObjectMgr::LoadBattleMastersEntry()
+void ObjectMgr::LoadGameObjectForQuests()
{
- mBattleMastersMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
-
- uint32 count = 0;
+ mGameObjectForQuestSet.clear(); // need for reload case
- if( !result )
+ if( !sGOStorage.MaxEntry )
{
barGoLink bar( 1 );
bar.step();
-
sLog.outString();
- sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
+ sLog.outString( ">> Loaded 0 GameObjects for quests" );
return;
}
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- ++count;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 entry = fields[0].GetUInt32();
- uint32 bgTypeId = fields[1].GetUInt32();
-
- mBattleMastersMap[entry] = bgTypeId;
-
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u battlemaster entries", count );
-}
-
-void ObjectMgr::LoadGameObjectForQuests()
-{
- mGameObjectForQuestSet.clear(); // need for reload case
-
+ barGoLink bar( sGOStorage.MaxEntry - 1 );
uint32 count = 0;
// collect GO entries for GO that must activated
for(uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry)
{
+ bar.step();
GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(go_entry);
if(!goInfo)
continue;
@@ -6265,7 +6817,7 @@ void ObjectMgr::LoadGameObjectForQuests()
}
sLog.outString();
- sLog.outString( ">> Loaded %u GameObject for quests", count );
+ sLog.outString( ">> Loaded %u GameObjects for quests", count );
}
bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value)
@@ -6291,7 +6843,7 @@ bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 mi
bar.step();
- sLog.outString("");
+ sLog.outString();
if(min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings
sLog.outErrorDb(">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.",table);
else
@@ -6534,17 +7086,17 @@ bool PlayerCondition::Meets(Player const * player) const
case CONDITION_NONE:
return true; // empty condition, always met
case CONDITION_AURA:
- return player->HasAura(value1, value2);
+ return player->HasAuraEffect(value1, value2);
case CONDITION_ITEM:
return player->HasItemCount(value1, value2);
case CONDITION_ITEM_EQUIPPED:
- return player->GetItemOrItemWithGemEquipped(value1) != NULL;
+ return player->HasItemOrGemWithIdEquipped(value1,1);
case CONDITION_ZONEID:
return player->GetZoneId() == value1;
case CONDITION_REPUTATION_RANK:
{
FactionEntry const* faction = sFactionStore.LookupEntry(value1);
- return faction && player->GetReputationRank(faction) >= value2;
+ return faction && player->GetReputationMgr().GetRank(faction) >= value2;
}
case CONDITION_TEAM:
return player->GetTeam() == value1;
@@ -6561,12 +7113,12 @@ bool PlayerCondition::Meets(Player const * player) const
{
Unit::AuraMap const& auras = player->GetAuras();
for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual==3580)
+ if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual[0]==3580)
return true;
return false;
}
case CONDITION_NO_AURA:
- return !player->HasAura(value1, value2);
+ return !player->HasAuraEffect(value1, value2);
case CONDITION_ACTIVE_EVENT:
return gameeventmgr.IsActiveEvent(value1);
case CONDITION_INSTANCE_DATA:
@@ -6711,7 +7263,7 @@ bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 val
}
case CONDITION_ACTIVE_EVENT:
{
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
if(value1 >=events.size() || !events[value1].isValid())
{
sLog.outErrorDb("Active event condition requires existed event id (%u), skipped", value1);
@@ -6722,6 +7274,8 @@ bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 val
case CONDITION_INSTANCE_DATA:
//TODO: need some check
break;
+ case CONDITION_NONE:
+ break;
}
return true;
}
@@ -6738,7 +7292,7 @@ SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
return SKILL_RANGE_MONO;
case SKILL_CATEGORY_ARMOR:
case SKILL_CATEGORY_CLASS:
- if(pSkill->id != SKILL_POISONS && pSkill->id != SKILL_LOCKPICKING)
+ if(pSkill->id != SKILL_LOCKPICKING)
return SKILL_RANGE_MONO;
else
return SKILL_RANGE_LEVEL;
@@ -6753,7 +7307,7 @@ SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
return SKILL_RANGE_MONO;
default:
case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc
- case SKILL_CATEGORY_NOT_DISPLAYED: //only GENEREC(DND)
+ case SKILL_CATEGORY_GENERIC: //only GENERIC(DND)
return SKILL_RANGE_NONE;
}
}
@@ -6814,11 +7368,10 @@ void ObjectMgr::LoadGameTele()
++count;
}
while (result->NextRow());
-
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u game tele's", count );
+ sLog.outString( ">> Loaded %u GameTeleports", count );
}
GameTele const* ObjectMgr::GetGameTele(const std::string& name) const
@@ -6954,30 +7507,41 @@ void ObjectMgr::LoadTrainerSpell()
continue;
}
- TrainerSpell* pTrainerSpell = new TrainerSpell();
- pTrainerSpell->spell = spell;
- pTrainerSpell->spellcost = fields[2].GetUInt32();
- pTrainerSpell->reqskill = fields[3].GetUInt32();
- pTrainerSpell->reqskillvalue = fields[4].GetUInt32();
- pTrainerSpell->reqlevel = fields[5].GetUInt32();
+ TrainerSpellData& data = m_mCacheTrainerSpellMap[entry];
- if(!pTrainerSpell->reqlevel)
- pTrainerSpell->reqlevel = spellinfo->spellLevel;
+ TrainerSpell& trainerSpell = data.spellList[spell];
+ trainerSpell.spell = spell;
+ trainerSpell.spellCost = fields[2].GetUInt32();
+ trainerSpell.reqSkill = fields[3].GetUInt32();
+ trainerSpell.reqSkillValue = fields[4].GetUInt32();
+ trainerSpell.reqLevel = fields[5].GetUInt32();
+ if(!trainerSpell.reqLevel)
+ trainerSpell.reqLevel = spellinfo->spellLevel;
- TrainerSpellData& data = m_mCacheTrainerSpellMap[entry];
+ // calculate learned spell for profession case when stored cast-spell
+ trainerSpell.learnedSpell = spell;
+ for(int i = 0; i <3; ++i)
+ {
+ if(spellinfo->Effect[i] != SPELL_EFFECT_LEARN_SPELL)
+ continue;
+ if(SpellMgr::IsProfessionOrRidingSpell(spellinfo->EffectTriggerSpell[i]))
+ {
+ trainerSpell.learnedSpell = spellinfo->EffectTriggerSpell[i];
+ break;
+ }
+ }
- if(SpellMgr::IsProfessionSpell(spell))
+ if(SpellMgr::IsProfessionSpell(trainerSpell.learnedSpell))
data.trainerType = 2;
- data.spellList.push_back(pTrainerSpell);
++count;
} while (result->NextRow());
delete result;
sLog.outString();
- sLog.outString( ">> Loaded Trainers %d", count );
+ sLog.outString( ">> Loaded %d Trainers", count );
}
void ObjectMgr::LoadVendors()
@@ -7255,16 +7819,30 @@ void ObjectMgr::LoadScriptNames()
"SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' "
"UNION "
"SELECT DISTINCT(script) FROM instance_template WHERE script <> ''");
- if(result)
+
+ if( !result )
{
- do
- {
- m_scriptNames.push_back((*result)[0].GetString());
- } while (result->NextRow());
- delete result;
+ barGoLink bar( 1 );
+ bar.step();
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded empty set of Script Names!");
+ return;
}
+ barGoLink bar( result->GetRowCount() );
+ uint32 count = 0;
+
+ do
+ {
+ bar.step();
+ m_scriptNames.push_back((*result)[0].GetString());
+ ++count;
+ } while (result->NextRow());
+ delete result;
+
std::sort(m_scriptNames.begin(), m_scriptNames.end());
+ sLog.outString();
+ sLog.outString( ">> Loaded %d Script Names", count );
}
uint32 ObjectMgr::GetScriptId(const char *name)
@@ -7284,13 +7862,16 @@ void ObjectMgr::CheckScripts(ScriptMapMap const& scripts,std::set<int32>& ids)
{
for(ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM)
{
- if(itrM->second.dataint)
+ switch(itrM->second.command)
{
- if(!GetTrinityStringLocale (itrM->second.dataint))
- sLog.outErrorDb( "Table `db_script_string` has not existed string id %u", itrM->first);
+ case SCRIPT_COMMAND_TALK:
+ {
+ if(!GetTrinityStringLocale (itrM->second.dataint))
+ sLog.outErrorDb( "Table `db_script_string` not has string id %u used db script (ID: %u)", itrM->second.dataint, itrMM->first);
- if(ids.count(itrM->second.dataint))
- ids.erase(itrM->second.dataint);
+ if(ids.count(itrM->second.dataint))
+ ids.erase(itrM->second.dataint);
+ }
}
}
}
@@ -7357,16 +7938,6 @@ CreatureInfo const *GetCreatureInfo(uint32 id)
return objmgr.GetCreatureTemplate(id);
}
-CreatureInfo const* GetCreatureTemplateStore(uint32 entry)
-{
- return sCreatureStorage.LookupEntry<CreatureInfo>(entry);
-}
-
-Quest const* GetQuestTemplateStore(uint32 entry)
-{
- return objmgr.GetQuestTemplate(entry);
-}
-
void ObjectMgr::LoadTransportEvents()
{
@@ -7403,3 +7974,12 @@ void ObjectMgr::LoadTransportEvents()
delete result;
}
+CreatureInfo const* GetCreatureTemplateStore(uint32 entry)
+{
+ return sCreatureStorage.LookupEntry<CreatureInfo>(entry);
+}
+
+Quest const* GetQuestTemplateStore(uint32 entry)
+{
+ return objmgr.GetQuestTemplate(entry);
+}