diff --git a/src/game/ChatCommands/Level3.cpp b/src/game/ChatCommands/Level3.cpp index a3197db65..e0e1989a5 100644 --- a/src/game/ChatCommands/Level3.cpp +++ b/src/game/ChatCommands/Level3.cpp @@ -637,6 +637,10 @@ bool ChatHandler::HandleReloadNpcTextCommand(char* /*args*/) bool ChatHandler::HandleReloadNpcTrainerCommand(char* /*args*/) { + sLog.outString("Re-Loading `npc_trainer_template` Table!"); + sObjectMgr.LoadTrainerTemplates(); + SendGlobalSysMessage("DB table `npc_trainer_template` reloaded."); + sLog.outString("Re-Loading `npc_trainer` Table!"); sObjectMgr.LoadTrainers(); SendGlobalSysMessage("DB table `npc_trainer` reloaded."); @@ -646,6 +650,10 @@ bool ChatHandler::HandleReloadNpcTrainerCommand(char* /*args*/) bool ChatHandler::HandleReloadNpcVendorCommand(char* /*args*/) { // not safe reload vendor template tables independent... + sLog.outString("Re-Loading `npc_vendor_template` Table!"); + sObjectMgr.LoadVendorTemplates(); + SendGlobalSysMessage("DB table `npc_vendor_template` reloaded."); + sLog.outString("Re-Loading `npc_vendor` Table!"); sObjectMgr.LoadVendors(); SendGlobalSysMessage("DB table `npc_vendor` reloaded."); diff --git a/src/game/Object/ObjectMgr.cpp b/src/game/Object/ObjectMgr.cpp index 7f57204e7..b838bb168 100644 --- a/src/game/Object/ObjectMgr.cpp +++ b/src/game/Object/ObjectMgr.cpp @@ -9408,6 +9408,41 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates) sLog.outString(">> Loaded %d trainer %sspells", count, isTemplates ? "template " : ""); } +void ObjectMgr::LoadTrainerTemplates() +{ + LoadTrainers("npc_trainer_template", true); + + // post loading check + std::set trainer_ids; + bool hasErrored = false; + + for (CacheTrainerSpellMap::const_iterator tItr = m_mCacheTrainerTemplateSpellMap.begin(); tItr != m_mCacheTrainerTemplateSpellMap.end(); ++tItr) + { trainer_ids.insert(tItr->first); } + + for (uint32 i = 1; i < sCreatureStorage.GetMaxEntry(); ++i) + { + if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) + { + if (cInfo->TrainerTemplateId) + { + if (m_mCacheTrainerTemplateSpellMap.find(cInfo->TrainerTemplateId) != m_mCacheTrainerTemplateSpellMap.end()) + { trainer_ids.erase(cInfo->TrainerTemplateId); } + else + { + sLog.outErrorDb("Creature (Entry: %u) has TrainerTemplateId = %u for nonexistent trainer template", cInfo->Entry, cInfo->TrainerTemplateId); + hasErrored = true; + } + } + } + } + + for (std::set::const_iterator tItr = trainer_ids.begin(); tItr != trainer_ids.end(); ++tItr) + { sLog.outErrorDb("Table `npc_trainer_template` has trainer template %u not used by any trainers ", *tItr); } + + if (hasErrored || !trainer_ids.empty()) // Append extra line in case of reported errors + { sLog.outString(); } +} + void ObjectMgr::LoadVendors(char const* tableName, bool isTemplates) { CacheVendorItemMap& vendorList = isTemplates ? m_mCacheVendorTemplateItemMap : m_mCacheVendorItemMap; @@ -9464,6 +9499,34 @@ void ObjectMgr::LoadVendors(char const* tableName, bool isTemplates) } +void ObjectMgr::LoadVendorTemplates() +{ + LoadVendors("npc_vendor_template", true); + + // post loading check + std::set vendor_ids; + + for (CacheVendorItemMap::const_iterator vItr = m_mCacheVendorTemplateItemMap.begin(); vItr != m_mCacheVendorTemplateItemMap.end(); ++vItr) + vendor_ids.insert(vItr->first); + + for (uint32 i = 1; i < sCreatureStorage.GetMaxEntry(); ++i) + { + if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) + { + if (cInfo->VendorTemplateId) + { + if (m_mCacheVendorTemplateItemMap.find(cInfo->VendorTemplateId) != m_mCacheVendorTemplateItemMap.end()) + vendor_ids.erase(cInfo->VendorTemplateId); + else + sLog.outErrorDb("Creature (Entry: %u) has VendorTemplateId = %u for nonexistent vendor template", cInfo->Entry, cInfo->VendorTemplateId); + } + } + } + + for (std::set::const_iterator vItr = vendor_ids.begin(); vItr != vendor_ids.end(); ++vItr) + sLog.outErrorDb("Table `npc_vendor_template` has vendor template %u not used by any vendors ", *vItr); +} + /* This function is supposed to take care of three things: * 1) Load Transports on Map or on Continents * 2) Load Active Npcs on Map or Continents diff --git a/src/game/Object/ObjectMgr.h b/src/game/Object/ObjectMgr.h index 49f6625ca..22c627201 100644 --- a/src/game/Object/ObjectMgr.h +++ b/src/game/Object/ObjectMgr.h @@ -825,7 +825,9 @@ class ObjectMgr void LoadGossipMenus(); + void LoadVendorTemplates(); void LoadVendors() { LoadVendors("npc_vendor", false); } + void LoadTrainerTemplates(); void LoadTrainers() { LoadTrainers("npc_trainer", false); } /// @param _map Map* of the map for which to load active entities. If NULL active entities on continents are loaded diff --git a/src/game/WorldHandlers/NPCHandler.cpp b/src/game/WorldHandlers/NPCHandler.cpp index b287ddf7d..d238b76ac 100644 --- a/src/game/WorldHandlers/NPCHandler.cpp +++ b/src/game/WorldHandlers/NPCHandler.cpp @@ -255,13 +255,18 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data) // check present spell in trainer spell list TrainerSpellData const* cSpells = unit->GetTrainerSpells(); + TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells(); - if (!cSpells) + if (!cSpells && !tSpells) trainState = 1; // Try find spell in npc_trainer TrainerSpell const* trainer_spell = cSpells ? cSpells->Find(spellId) : NULL; + // Not found, try find in npc_trainer_template + if (!trainer_spell && tSpells) + trainer_spell = tSpells->Find(spellId); + // Not found anywhere, cheating? if (!trainer_spell) trainState = 1; diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 512cfc706..805581554 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -1353,9 +1353,11 @@ void World::SetInitialWorldSettings() sObjectMgr.LoadGossipMenus(); sLog.outString("Loading Vendors..."); + sObjectMgr.LoadVendorTemplates(); // must be after load ItemTemplate sObjectMgr.LoadVendors(); // must be after load CreatureTemplate, VendorTemplate, and ItemTemplate sLog.outString("Loading Trainers..."); + sObjectMgr.LoadTrainerTemplates(); // must be after load CreatureTemplate sObjectMgr.LoadTrainers(); // must be after load CreatureTemplate, TrainerTemplate sLog.outString("Loading Waypoint scripts..."); // before loading from creature_movement diff --git a/src/shared/revision.h b/src/shared/revision.h index f0b7b5920..28f1f9181 100644 --- a/src/shared/revision.h +++ b/src/shared/revision.h @@ -28,16 +28,16 @@ #define REALMD_DB_VERSION_NR 21 #define REALMD_DB_STRUCTURE_NR 1 - #define REALMD_DB_CONTENT_NR 3 - #define REALMD_DB_UPDATE_DESCRIPTION "Remove field from dbDocs" + #define REALMD_DB_CONTENT_NR 4 + #define REALMD_DB_UPDATE_DESCRIPTION "Remove dbDocs" #define CHAR_DB_VERSION_NR 21 #define CHAR_DB_STRUCTURE_NR 3 - #define CHAR_DB_CONTENT_NR 1 - #define CHAR_DB_UPDATE_DESCRIPTION "characters_pvpstats" + #define CHAR_DB_CONTENT_NR 2 + #define CHAR_DB_UPDATE_DESCRIPTION "Remove DbDocs" #define WORLD_DB_VERSION_NR 21 - #define WORLD_DB_STRUCTURE_NR 7 - #define WORLD_DB_CONTENT_NR 8 - #define WORLD_DB_UPDATE_DESCRIPTION "kodo_roundup_tidyup" + #define WORLD_DB_STRUCTURE_NR 8 + #define WORLD_DB_CONTENT_NR 1 + #define WORLD_DB_UPDATE_DESCRIPTION "force_version_change" #endif // __REVISION_H__