diff options
Diffstat (limited to 'src/game/ObjectMgr.cpp')
-rw-r--r-- | src/game/ObjectMgr.cpp | 1769 |
1 files changed, 1228 insertions, 541 deletions
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 227b0f90f28..8f87e58ed26 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_) @@ -189,7 +167,7 @@ ObjectMgr::~ObjectMgr() void ObjectMgr::LoadPlayerInfoInCache() { - QueryResult *result = CharacterDatabase.PQuery("SELECT guid, name, data, class FROM characters"); + QueryResult *result = CharacterDatabase.PQuery("SELECT guid, name, data, class FROM characters"); if(!result) { sLog.outError( "Loading Player Cache failed."); @@ -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)); } @@ -523,21 +553,27 @@ void ObjectMgr::LoadCreatureTemplates() continue; } + if(cInfo->unit_class != heroicInfo->unit_class) + { + sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in heroic mode (Entry: %u, class %u).",i, cInfo->unit_class, cInfo->HeroicEntry, heroicInfo->unit_class); + continue; + } + if(cInfo->npcflag != heroicInfo->npcflag) { sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `npcflag` in heroic mode.",i); continue; } - if(cInfo->classNum != heroicInfo->classNum) + if(cInfo->trainer_class != heroicInfo->trainer_class) { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `classNum` in heroic mode.",i); + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); continue; } - if(cInfo->race != heroicInfo->race) + if(cInfo->trainer_race != heroicInfo->trainer_race) { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `race` in heroic mode.",i); + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); continue; } @@ -553,6 +589,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); } @@ -587,6 +635,9 @@ void ObjectMgr::LoadCreatureTemplates() const_cast<CreatureInfo*>(cInfo)->Modelid_H2 = 0; } + if (cInfo->unit_class && ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0) + sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class); + if(cInfo->dmgschool >= MAX_SPELL_SCHOOL) { sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool); @@ -602,6 +653,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 +679,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); @@ -729,6 +802,15 @@ void ObjectMgr::LoadCreatureAddons() if(!addon) continue; + if (addon->mount) + { + if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount)) + sLog.outErrorDb("Creature (Entry %u) have invalid displayInfoId for mount (%u) defined in `creature_template_addon`.",addon->guidOrEntry, addon->mount); + } + + if (!sEmotesStore.LookupEntry(addon->emote)) + sLog.outErrorDb("Creature (Entry %u) have invalid emote (%u) defined in `creature_template_addon`.",addon->guidOrEntry, addon->emote); + ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_template_addon", "Entry"); if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry)) @@ -747,6 +829,15 @@ void ObjectMgr::LoadCreatureAddons() if(!addon) continue; + if (addon->mount) + { + if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount)) + sLog.outErrorDb("Creature (GUID %u) have invalid displayInfoId for mount (%u) defined in `creature_addon`.",addon->guidOrEntry, addon->mount); + } + + if (!sEmotesStore.LookupEntry(addon->emote)) + sLog.outErrorDb("Creature (GUID %u) have invalid emote (%u) defined in `creature_addon`.",addon->guidOrEntry, addon->emote); + ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_addon", "GUIDLow"); if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end()) @@ -763,6 +854,42 @@ 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(); } @@ -780,7 +907,9 @@ uint32 ObjectMgr::ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const if (!data || data->displayid == 0) // use defaults from the template { display_id = cinfo->GetRandomValidModelId(); - } else display_id = data->displayid; // overwritten from creature data + } + else + display_id = data->displayid; // overwritten from creature data return display_id; } @@ -924,9 +1053,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 +1064,7 @@ void ObjectMgr::LoadCreatures() bar.step(); - sLog.outString(""); + sLog.outString(); sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty."); return; } @@ -946,6 +1076,9 @@ void ObjectMgr::LoadCreatures() if(cInfo->HeroicEntry) heroicCreatures.insert(cInfo->HeroicEntry); + //TODO: remove this + //gameeventmgr.mGameEventCreatureGuids.resize(52*2-1); + barGoLink bar(result->GetRowCount()); do @@ -953,11 +1086,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,20 +1114,25 @@ void ObjectMgr::LoadCreatures() data.is_dead = fields[14].GetBool(); data.movementType = fields[15].GetUInt8(); data.spawnMask = fields[16].GetUInt8(); - int16 gameEvent = fields[17].GetInt16(); + data.phaseMask = fields[17].GetUInt16(); + int16 gameEvent = fields[18].GetInt16(); + int16 PoolId = fields[19].GetInt16(); - CreatureInfo const* cInfo = GetCreatureTemplate(data.id); - if(!cInfo) + if(heroicCreatures.find(data.id)!=heroicCreatures.end()) { - sLog.outErrorDb("Table `creature` have creature (GUID: %u) with not existed creature entry %u, skipped.",guid,data.id ); + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template in `creature_template_substitution`, skipped.",guid,data.id ); continue; } - if(heroicCreatures.find(data.id)!=heroicCreatures.end()) + // I do not know why but in db most display id are not zero + /*if(data.displayid == 11686 || data.displayid == 24719) { - sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template in `creature_template_substitution`, skipped.",guid,data.id ); - continue; + (const_cast<CreatureInfo*>(cInfo))->flags_extra |= CREATURE_FLAG_EXTRA_TRIGGER; } + else if(data.displayid == cInfo->Modelid_A1 || data.displayid == cInfo->Modelid_A2 + || data.displayid == cInfo->Modelid_H1 || data.displayid == cInfo->Modelid_H2) + data.displayid = 0; + */ if(data.equipmentId > 0) // -1 no equipment, 0 use default { @@ -1003,6 +1149,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 ); @@ -1021,6 +1174,8 @@ void ObjectMgr::LoadCreatures() 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 ); data.movementType = IDLE_MOTION_TYPE; } + else if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) + data.movementType = IDLE_MOTION_TYPE; } else if(data.movementType == IDLE_MOTION_TYPE) { @@ -1031,8 +1186,29 @@ 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(entry == 32307 || entry == 32308) + /*if(entry == 30739 || entry == 30740) + { + gameEvent = 51; + uint32 guid2 = objmgr.GenerateLowGuid(HIGHGUID_UNIT); + CreatureData& data2 = mCreatureDataMap[guid2]; + data2 = data; +// data2.id = (entry == 32307 ? 32308 : 32307); + data2.id = (entry == 30739 ? 30740 : 30739); + data2.displayid = 0; + gameeventmgr.mGameEventCreatureGuids[51+51].push_back(guid); + gameeventmgr.mGameEventCreatureGuids[51+50].push_back(guid2); + }*/ + + 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 +1216,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) @@ -1075,15 +1251,112 @@ void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data) } } +uint32 ObjectMgr::AddGameObject(uint32 entry, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay, float rotation0, float rotation1, float rotation2, float rotation3) +{ + GameObjectInfo const* goinfo = GetGameObjectInfo(entry); + if (!goinfo) + return 0; + + uint32 guid = GenerateLowGuid(HIGHGUID_GAMEOBJECT); + GameObjectData& data = NewGOData(guid); + data.id = entry; + data.mapid = mapId; + data.posX = x; + data.posY = y; + data.posZ = z; + data.orientation = o; + data.rotation0 = rotation0; + data.rotation1 = rotation1; + data.rotation2 = rotation2; + data.rotation3 = rotation3; + data.spawntimesecs = spawntimedelay; + data.animprogress = 100; + data.spawnMask = 1; + data.go_state = GO_STATE_READY; + data.phaseMask = PHASEMASK_NORMAL; + data.dbData = false; + + AddGameobjectToGrid(guid, &data); + + // Spawn if necessary (loaded grids only) + if(Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(mapId))) + { + // We use spawn coords to spawn + if(!map->Instanceable() && !map->IsRemovalGrid(x, y)) + { + GameObject *go = new GameObject; + if(!go->LoadFromDB(guid, map)) + { + sLog.outError("AddGameObject: cannot add gameobject entry %u to map", entry); + delete go; + return 0; + } + map->Add(go); + } + } + + return guid; +} + +uint32 ObjectMgr::AddCreature(uint32 entry, uint32 team, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay) +{ + CreatureInfo const *cInfo = GetCreatureTemplate(entry); + if(!cInfo) + return 0; + + uint32 guid = GenerateLowGuid(HIGHGUID_UNIT); + CreatureData& data = NewOrExistCreatureData(guid); + data.id = entry; + data.mapid = mapId; + data.displayid = 0; + data.equipmentId = cInfo->equipmentId; + data.posX = x; + data.posY = y; + data.posZ = z; + data.orientation = o; + data.spawntimesecs = spawntimedelay; + data.spawndist = 0; + data.currentwaypoint = 0; + data.curhealth = cInfo->maxhealth; + data.curmana = cInfo->maxmana; + data.is_dead = false; + data.movementType = cInfo->MovementType; + data.spawnMask = 1; + data.phaseMask = PHASEMASK_NORMAL; + data.dbData = false; + + AddCreatureToGrid(guid, &data); + + // Spawn if necessary (loaded grids only) + if(Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(mapId))) + { + // We use spawn coords to spawn + if(!map->Instanceable() && !map->IsRemovalGrid(x, y)) + { + Creature* creature = new Creature; + if(!creature->LoadFromDB(guid, map)) + { + sLog.outError("AddCreature: cannot add creature entry %u to map", entry); + delete creature; + return 0; + } + map->Add(creature); + } + } + + return guid; +} + void ObjectMgr::LoadGameobjects() { uint32 count = 0; // 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 +1376,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 +1400,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 Entry: %u) with invalid rotation2 (%f) value, skip",guid,data.id,data.rotation2 ); + continue; + } + + 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) with not existed gameobject entry %u, skipped.",guid,data.id ); + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid coordinates, skip",guid,data.id ); continue; } - if (gameEvent==0) // if not this is to be managed by GameEvent System + 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 +1448,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 +1518,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 +1560,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 +1663,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 +1712,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 +1747,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 +1798,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 +1831,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 +1880,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 +1918,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 +1928,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 +1965,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 +1975,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 +1993,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 +2011,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 +2059,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 +2108,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 +2155,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 +2401,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; @@ -2033,8 +2435,18 @@ void ObjectMgr::LoadPlayerInfo() continue; } - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - pInfo->spell.push_back(CreateSpellPair(fields[2].GetUInt16(), fields[3].GetUInt8())); + if(!current_race || !current_class) + { + uint32 min_race = current_race ? current_race : 1; + uint32 max_race = current_race ? current_race + 1 : MAX_RACES; + uint32 min_class = current_class ? current_class : 1; + uint32 max_class = current_class ? current_class + 1 : MAX_CLASSES; + for(uint32 r = min_race; r < max_race; ++r) + for(uint32 c = min_class; c < max_class; ++c) + playerInfo[r][c].spell.push_back(fields[2].GetUInt32()); + } + else + playerInfo[current_race][current_class].spell.push_back(fields[2].GetUInt32()); bar.step(); ++count; @@ -2139,7 +2551,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 +2649,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 +2724,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 +3032,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 +3092,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 +3114,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 +3147,35 @@ 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 + "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4," + // 116 117 118 119 120 121 + "IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4," + // 122 123 124 125 + "OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4," + // 126 127 "StartScript, CompleteScript" " FROM quest_template"); if(result == NULL) @@ -2854,10 +3347,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 +3469,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 +3478,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 +3491,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 +3698,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 +3724,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 +3773,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 +3798,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,58 +3909,7 @@ void ObjectMgr::LoadQuestLocales() delete result; sLog.outString(); - sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() ); -} - -void ObjectMgr::LoadPetCreateSpells() -{ - QueryResult *result = WorldDatabase.Query("SELECT entry, Spell1, Spell2, Spell3, Spell4 FROM petcreateinfo_spell"); - if(!result) - { - barGoLink bar( 1 ); - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded 0 pet create spells" ); - sLog.outErrorDb("`petcreateinfo_spell` table is empty!"); - return; - } - - uint32 count = 0; - - barGoLink bar( result->GetRowCount() ); - - mPetCreateSpell.clear(); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 creature_id = fields[0].GetUInt32(); - - if(!creature_id || !sCreatureStorage.LookupEntry<CreatureInfo>(creature_id)) - continue; - - PetCreateSpellEntry PetCreateSpell; - for(int i = 0; i < 4; i++) - { - PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32(); - - if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i])) - sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]); - } - - mPetCreateSpell[creature_id] = PetCreateSpell; - - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u pet create spells", count ); + sLog.outString( ">> Loaded %lu Quest locale strings", (unsigned long)mQuestLocaleMap.size() ); } void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename) @@ -3584,6 +3979,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 +4117,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 +4140,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; } } @@ -3825,13 +4251,16 @@ void ObjectMgr::LoadEventScripts() switch(goInfo->type) { case GAMEOBJECT_TYPE_GOOBER: - if(goInfo->goober.eventId) + if (goInfo->goober.eventId) evt_scripts.insert(goInfo->goober.eventId); break; case GAMEOBJECT_TYPE_CHEST: - if(goInfo->chest.eventId) + if (goInfo->chest.eventId) evt_scripts.insert(goInfo->chest.eventId); break; + case GAMEOBJECT_TYPE_CAMERA: + if (goInfo->camera.eventID) + evt_scripts.insert(goInfo->camera.eventID); default: break; } @@ -3858,7 +4287,8 @@ void ObjectMgr::LoadEventScripts() { std::set<uint32>::const_iterator itr2 = evt_scripts.find(itr->first); if (itr2 == evt_scripts.end()) - sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field or type 3 data6 field or any spell effect %u", itr->first, SPELL_EFFECT_SEND_EVENT); + sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u", + itr->first, SPELL_EFFECT_SEND_EVENT); } } @@ -3968,7 +4398,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 +4435,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 +4465,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 +4492,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 +4528,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 +4579,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 +4630,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 @@ -4220,18 +4640,31 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec); //delete all old mails without item and without body immediately, if starting server if (!serverUp) - CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" I64FMTD "' AND has_items = '0' AND itemTextId = 0", (uint64)basetime); + CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" UI64FMTD "' AND has_items = '0' AND itemTextId = 0", (uint64)basetime); // 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); + QueryResult* result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,itemTextId,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" UI64FMTD "'", (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(); @@ -4284,7 +4717,7 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) else { //mail will be returned: - 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); + CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" UI64FMTD "', deliver_time = '" UI64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID); delete m; continue; } @@ -4297,8 +4730,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 +4892,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 +4901,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 +4955,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 +4963,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 +5110,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 +5121,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 +5165,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 +5313,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 +5354,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 +5465,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 +5475,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 +5493,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 +5512,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 +5545,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 +5618,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 +5697,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 +5755,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 +5787,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 +5808,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 +5884,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 +5989,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 +6072,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 +6280,131 @@ 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, quest_status, 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; + } + + } + + uint32 queststatus = fields[3].GetUInt32(); + + uint8 castFlags = fields[4].GetUInt8(); + SpellClickInfo info; + info.spellId = spellid; + info.questId = quest; + info.questStatus = queststatus; + 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 +6443,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); } } @@ -5822,7 +6473,7 @@ void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t; WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); if(t) - WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance); + WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ( '%u', '" UI64FMTD "', '%u' )", loguid, uint64(t), instance); } void ObjectMgr::DeleteCreatureData(uint32 guid) @@ -5840,7 +6491,7 @@ void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t) mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t; WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); if(t) - WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance); + WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ( '%u', '" UI64FMTD "', '%u' )", loguid, uint64(t), instance); } void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance) @@ -6021,11 +6672,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 +6692,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 +6851,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,34 +6905,55 @@ 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) { - // cleanup affected map part for reloading case - for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();) + int32 start_value = min_value; + int32 end_value = max_value; + // some string can have negative indexes range + if (start_value < 0) { - if(itr->first >= min_value && itr->first <= max_value) + if (end_value >= start_value) { - TrinityStringLocaleMap::iterator itr2 = itr; - ++itr; - mTrinityStringLocaleMap.erase(itr2); + sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.",table,min_value,max_value); + return false; + } + + // real range (max+1,min+1) exaple: (-10,-1000) -> -999...-10+1 + std::swap(start_value,end_value); + ++start_value; + ++end_value; + } + else + { + if (start_value >= end_value) + { + sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.",table,min_value,max_value); + return false; } + } + + // cleanup affected map part for reloading case + for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();) + { + if (itr->first >= start_value && itr->first < end_value) + mTrinityStringLocaleMap.erase(itr++); else ++itr; } 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); - if(!result) + if (!result) { barGoLink bar(1); bar.step(); - sLog.outString(""); - if(min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings + 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 sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table); @@ -6310,22 +6971,20 @@ bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 mi int32 entry = fields[0].GetInt32(); - if(entry==0) + if (entry==0) { sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.",table); continue; } - else if(entry < min_value || entry > max_value) + else if (entry < start_value || entry >= end_value) { - int32 start = min_value > 0 ? min_value : max_value; - int32 end = min_value > 0 ? max_value : min_value; - sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,start,end); + sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,min_value,max_value); continue; } TrinityStringLocale& data = mTrinityStringLocaleMap[entry]; - if(data.Content.size() > 0) + if (data.Content.size() > 0) { sLog.outErrorDb("Table `%s` contain data for already loaded entry %i (from another table?), ignored.",table,entry); continue; @@ -6340,13 +6999,13 @@ bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 mi for(int i = 1; i < MAX_LOCALE; ++i) { std::string str = fields[i+1].GetCppString(); - if(!str.empty()) + if (!str.empty()) { int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if(idx >= 0) + if (idx >= 0) { // 0 -> default, idx in to idx+1 - if(data.Content.size() <= idx+1) + if (data.Content.size() <= idx+1) data.Content.resize(idx+2); data.Content[idx+1] = str; @@ -6358,7 +7017,7 @@ bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 mi delete result; sLog.outString(); - if(min_value == MIN_TRINITY_STRING_ID) // internal Trinity strings + if (min_value == MIN_TRINITY_STRING_ID) sLog.outString( ">> Loaded %u Trinity strings from table %s", count,table); else sLog.outString( ">> Loaded %u string templates from %s", count,table); @@ -6534,17 +7193,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 +7220,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 +7370,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 +7381,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 +7399,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 +7414,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 +7475,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 +7614,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 +7926,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 +7969,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); + } } } } @@ -7326,15 +8014,15 @@ uint32 GetAreaTriggerScriptId(uint32 trigger_id) bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value) { - if(start_value >= 0 || start_value <= end_value) // start/end reversed for negative values + // MAX_DB_SCRIPT_STRING_ID is max allowed negative value for scripts (scrpts can use only more deep negative values + // start/end reversed for negative values + if (start_value > MAX_DB_SCRIPT_STRING_ID || end_value >= start_value) { - 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()); - start_value = -1; - end_value = std::numeric_limits<int32>::min(); + sLog.outErrorDb("Table '%s' attempt loaded with reserved by mangos range (%d - %d), strings not loaded.",table,start_value,end_value+1); + return false; } - // for scripting localized strings allowed use _only_ negative entries - return objmgr.LoadTrinityStrings(db,table,end_value,start_value); + return objmgr.LoadTrinityStrings(db,table,start_value,end_value); } uint32 TRINITY_DLL_SPEC GetScriptId(const char *name) @@ -7357,16 +8045,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 +8081,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); +} |