diff options
Diffstat (limited to 'src/server/game/Globals/ObjectMgr.cpp')
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 324 |
1 files changed, 165 insertions, 159 deletions
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 89fb1ab8a01..2efdbfb015b 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -19,6 +19,7 @@ #include "ObjectMgr.h" #include "ArenaTeamMgr.h" #include "Chat.h" +#include "Containers.h" #include "DatabaseEnv.h" #include "DB2Stores.h" #include "DisableMgr.h" @@ -285,8 +286,6 @@ ObjectMgr::~ObjectMgr() for (CacheVendorItemContainer::iterator itr = _cacheVendorItemStore.begin(); itr != _cacheVendorItemStore.end(); ++itr) itr->second.Clear(); - _cacheTrainerSpellStore.clear(); - for (DungeonEncounterContainer::iterator itr =_dungeonEncounterStore.begin(); itr != _dungeonEncounterStore.end(); ++itr) for (DungeonEncounterList::iterator encounterItr = itr->second.begin(); encounterItr != itr->second.end(); ++encounterItr) delete *encounterItr; @@ -425,15 +424,15 @@ void ObjectMgr::LoadCreatureTemplates() "modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, " // 20 21 22 23 24 25 26 27 28 29 30 "faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, " - // 31 32 33 34 35 36 37 38 39 40 - "unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_type, trainer_class, trainer_race, type, " - // 41 42 43 44 45 46 47 48 49 50 51 + // 31 32 33 34 35 36 37 38 + "unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, " + // 39 40 41 42 43 44 45 46 47 48 49 "type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, " - // 52 53 54 55 56 57 58 59 60 61 62 63 64 + // 50 51 52 53 54 55 56 57 58 59 60 61 62 "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, " - // 65 66 67 68 69 70 71 72 73 + // 63 64 65 66 67 68 69 70 71 "InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, " - // 74 75 76 77 78 79 + // 72 73 74 75 76 77 "RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template"); if (!result) @@ -504,42 +503,40 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.unit_flags3 = fields[34].GetUInt32(); creatureTemplate.dynamicflags = fields[35].GetUInt32(); creatureTemplate.family = CreatureFamily(fields[36].GetUInt8()); - creatureTemplate.trainer_type = uint32(fields[37].GetUInt8()); - creatureTemplate.trainer_class = uint32(fields[38].GetUInt8()); - creatureTemplate.trainer_race = uint32(fields[39].GetUInt8()); - creatureTemplate.type = uint32(fields[40].GetUInt8()); - creatureTemplate.type_flags = fields[41].GetUInt32(); - creatureTemplate.type_flags2 = fields[42].GetUInt32(); - creatureTemplate.lootid = fields[43].GetUInt32(); - creatureTemplate.pickpocketLootId = fields[44].GetUInt32(); - creatureTemplate.SkinLootId = fields[45].GetUInt32(); + creatureTemplate.trainer_class = uint32(fields[37].GetUInt8()); + creatureTemplate.type = uint32(fields[38].GetUInt8()); + creatureTemplate.type_flags = fields[39].GetUInt32(); + creatureTemplate.type_flags2 = fields[40].GetUInt32(); + creatureTemplate.lootid = fields[41].GetUInt32(); + creatureTemplate.pickpocketLootId = fields[42].GetUInt32(); + creatureTemplate.SkinLootId = fields[43].GetUInt32(); for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - creatureTemplate.resistance[i] = fields[46 + i - 1].GetInt16(); + creatureTemplate.resistance[i] = fields[44 + i - 1].GetInt16(); for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i) - creatureTemplate.spells[i] = fields[52 + i].GetUInt32(); - - creatureTemplate.VehicleId = fields[60].GetUInt32(); - creatureTemplate.mingold = fields[61].GetUInt32(); - creatureTemplate.maxgold = fields[62].GetUInt32(); - creatureTemplate.AIName = fields[63].GetString(); - creatureTemplate.MovementType = uint32(fields[64].GetUInt8()); - creatureTemplate.InhabitType = uint32(fields[65].GetUInt8()); - creatureTemplate.HoverHeight = fields[66].GetFloat(); - creatureTemplate.ModHealth = fields[67].GetFloat(); - creatureTemplate.ModHealthExtra = fields[68].GetFloat(); - creatureTemplate.ModMana = fields[69].GetFloat(); - creatureTemplate.ModManaExtra = fields[70].GetFloat(); - creatureTemplate.ModArmor = fields[71].GetFloat(); - creatureTemplate.ModDamage = fields[72].GetFloat(); - creatureTemplate.ModExperience = fields[73].GetFloat(); - creatureTemplate.RacialLeader = fields[74].GetBool(); - creatureTemplate.movementId = fields[75].GetUInt32(); - creatureTemplate.RegenHealth = fields[76].GetBool(); - creatureTemplate.MechanicImmuneMask = fields[77].GetUInt32(); - creatureTemplate.flags_extra = fields[78].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[79].GetString()); + creatureTemplate.spells[i] = fields[50 + i].GetUInt32(); + + creatureTemplate.VehicleId = fields[58].GetUInt32(); + creatureTemplate.mingold = fields[59].GetUInt32(); + creatureTemplate.maxgold = fields[60].GetUInt32(); + creatureTemplate.AIName = fields[61].GetString(); + creatureTemplate.MovementType = uint32(fields[62].GetUInt8()); + creatureTemplate.InhabitType = uint32(fields[63].GetUInt8()); + creatureTemplate.HoverHeight = fields[64].GetFloat(); + creatureTemplate.ModHealth = fields[65].GetFloat(); + creatureTemplate.ModHealthExtra = fields[66].GetFloat(); + creatureTemplate.ModMana = fields[67].GetFloat(); + creatureTemplate.ModManaExtra = fields[68].GetFloat(); + creatureTemplate.ModArmor = fields[69].GetFloat(); + creatureTemplate.ModDamage = fields[70].GetFloat(); + creatureTemplate.ModExperience = fields[71].GetFloat(); + creatureTemplate.RacialLeader = fields[72].GetBool(); + creatureTemplate.movementId = fields[73].GetUInt32(); + creatureTemplate.RegenHealth = fields[74].GetBool(); + creatureTemplate.MechanicImmuneMask = fields[75].GetUInt32(); + creatureTemplate.flags_extra = fields[76].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[77].GetString()); } void ObjectMgr::LoadCreatureTemplateAddons() @@ -772,24 +769,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) continue; } - if (cInfo->trainer_race != difficultyInfo->trainer_race) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, trainer_race: %u) has different `trainer_race` in difficulty %u mode (Entry: %u, trainer_race: %u).", - cInfo->Entry, cInfo->trainer_race, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->trainer_race); - TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `trainer_race`=%u WHERE `entry`=%u;", - cInfo->trainer_race, cInfo->DifficultyEntry[diff]); - continue; - } - - if (cInfo->trainer_type != difficultyInfo->trainer_type) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, trainer_type: %u) has different `trainer_type` in difficulty %u mode (Entry: %u, trainer_type: %u).", - cInfo->Entry, cInfo->trainer_type, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->trainer_type); - TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `trainer_type`=%u WHERE `entry`=%u;", - cInfo->trainer_type, cInfo->DifficultyEntry[diff]); - continue; - } - if (cInfo->type != difficultyInfo->type) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, type: %u) has different `type` in difficulty %u mode (Entry: %u, type: %u).", @@ -953,9 +932,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) if (cInfo->RangeAttackTime == 0) const_cast<CreatureTemplate*>(cInfo)->RangeAttackTime = BASE_ATTACK_TIME; - if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE) - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong trainer type %u.", cInfo->Entry, cInfo->trainer_type); - if (cInfo->speed_walk == 0.0f) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%f) in speed_walk, set to 1.", cInfo->Entry, cInfo->speed_walk); @@ -8494,118 +8470,126 @@ void ObjectMgr::LoadMailLevelRewards() TC_LOG_INFO("server.loading", ">> Loaded %u level dependent mail rewards in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::AddSpellToTrainer(uint32 ID, uint32 SpellID, uint32 MoneyCost, uint32 ReqSkillLine, uint32 ReqSkillRank, uint32 ReqLevel, uint32 Index) +void ObjectMgr::LoadTrainers() { - if (ID >= TRINITY_TRAINER_START_REF) - return; + uint32 oldMSTime = getMSTime(); - CreatureTemplate const* cInfo = GetCreatureTemplate(ID); - if (!cInfo) - { - TC_LOG_ERROR("sql.sql", "Table `npc_trainer` contains entries for a non-existing creature template (ID: %u), ignoring", ID); - return; - } + // For reload case + _trainers.clear(); - if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER)) + std::unordered_map<int32, std::vector<Trainer::Spell>> spellsByTrainer; + if (QueryResult trainerSpellsResult = WorldDatabase.Query("SELECT TrainerId, SpellId, MoneyCost, ReqSkillLine, ReqSkillRank, ReqAbility1, ReqAbility2, ReqAbility3, ReqLevel FROM trainer_spell")) { - TC_LOG_ERROR("sql.sql", "Table `npc_trainer` contains entries for a creature template (ID: %u) without any trainer flag, ignoring", ID); - return; - } + do + { + Field* fields = trainerSpellsResult->Fetch(); - SpellInfo const* spellinfo = sSpellMgr->GetSpellInfo(SpellID); - if (!spellinfo) - { - TC_LOG_ERROR("sql.sql", "Table `npc_trainer` contains an ID (%u) for a non-existing spell (Spell: %u), ignoring", ID, SpellID); - return; - } + Trainer::Spell spell; + uint32 trainerId = fields[0].GetUInt32(); + spell.SpellId = fields[1].GetUInt32(); + spell.MoneyCost = fields[2].GetUInt32(); + spell.ReqSkillLine = fields[3].GetUInt32(); + spell.ReqSkillRank = fields[4].GetUInt32(); + spell.ReqAbility[0] = fields[5].GetUInt32(); + spell.ReqAbility[1] = fields[6].GetUInt32(); + spell.ReqAbility[2] = fields[7].GetUInt32(); + spell.ReqLevel = fields[8].GetUInt8(); - if (!SpellMgr::IsSpellValid(spellinfo)) - { - TC_LOG_ERROR("sql.sql", "Table `npc_trainer` contains an ID (%u) for a broken spell (Spell: %u), ignoring", ID, SpellID); - return; - } + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell.SpellId); + if (!spellInfo) + { + TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing spell (SpellId: %u) for TrainerId %u, ignoring", spell.SpellId, trainerId); + continue; + } - TrainerSpellData& data = _cacheTrainerSpellStore[ID]; + if (spell.ReqSkillLine && !sSkillLineStore.LookupEntry(spell.ReqSkillLine)) + { + TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing skill (ReqSkillLine: %u) for TrainerId %u and SpellId %u, ignoring", + spell.ReqSkillLine, spell.SpellId, trainerId); + continue; + } - TrainerSpell& trainerSpell = data.spellList[SpellID]; - trainerSpell.SpellID = SpellID; - trainerSpell.MoneyCost = MoneyCost; - trainerSpell.ReqSkillLine = ReqSkillLine; - trainerSpell.ReqSkillRank = ReqSkillRank; - trainerSpell.ReqLevel = ReqLevel; - trainerSpell.Index = Index; + bool allReqValid = true; + for (std::size_t i = 0; i < spell.ReqAbility.size(); ++i) + { + uint32 requiredSpell = spell.ReqAbility[i]; + if (requiredSpell && !sSpellMgr->GetSpellInfo(requiredSpell)) + { + TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing spell (ReqAbility" SZFMTD ": %u) for TrainerId %u and SpellId %u, ignoring", + i + 1, requiredSpell, spell.SpellId, trainerId); + allReqValid = false; + } + } - if (!trainerSpell.ReqLevel) - trainerSpell.ReqLevel = spellinfo->SpellLevel; + if (!allReqValid) + continue; - // calculate learned spell for profession case when stored cast-spell - trainerSpell.ReqAbility[0] = SpellID; - for (SpellEffectInfo const* effect : spellinfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) - { - if (!effect || effect->Effect != SPELL_EFFECT_LEARN_SPELL) - continue; - if (trainerSpell.ReqAbility[0] == SpellID) - trainerSpell.ReqAbility[0] = 0; - // player must be able to cast spell on himself - if (effect->TargetA.GetTarget() != 0 && effect->TargetA.GetTarget() != TARGET_UNIT_TARGET_ALLY - && effect->TargetA.GetTarget() != TARGET_UNIT_TARGET_ANY && effect->TargetA.GetTarget() != TARGET_UNIT_CASTER) - { - TC_LOG_ERROR("sql.sql", "Table `npc_trainer` has spell %u for trainer entry %u with learn effect which has incorrect target type, ignoring learn effect!", SpellID, ID); - continue; - } + for (SpellEffectInfo const* spellEffect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + { + if (spellEffect->IsEffect(SPELL_EFFECT_LEARN_SPELL)) + { + spell.CastSpellId = spell.SpellId; + spell.SpellId = spellEffect->TriggerSpell; + break; + } + } - trainerSpell.ReqAbility[effect->EffectIndex] = effect->TriggerSpell; + spellsByTrainer[trainerId].push_back(spell); - if (trainerSpell.ReqAbility[effect->EffectIndex]) - { - SpellInfo const* learnedSpellInfo = sSpellMgr->GetSpellInfo(trainerSpell.ReqAbility[effect->EffectIndex]); - if (learnedSpellInfo && learnedSpellInfo->IsProfession()) - data.trainerType = 2; - } + } while (trainerSpellsResult->NextRow()); } - return; -} - -void ObjectMgr::LoadTrainerSpell() -{ - uint32 oldMSTime = getMSTime(); + if (QueryResult trainersResult = WorldDatabase.Query("SELECT Id, Type, Greeting FROM trainer")) + { + do + { + Field* fields = trainersResult->Fetch(); + uint32 trainerId = fields[0].GetUInt32(); + Trainer::Type trainerType = Trainer::Type(fields[1].GetUInt8()); + std::string greeting = fields[2].GetString(); + std::vector<Trainer::Spell> spells; + auto spellsItr = spellsByTrainer.find(trainerId); + if (spellsItr != spellsByTrainer.end()) + { + spells = std::move(spellsItr->second); + spellsByTrainer.erase(spellsItr); + } - // For reload case - _cacheTrainerSpellStore.clear(); + _trainers.emplace(std::piecewise_construct, std::forward_as_tuple(trainerId), std::forward_as_tuple(trainerId, trainerType, std::move(greeting), std::move(spells))); - QueryResult result = WorldDatabase.Query("SELECT b.ID, a.SpellID, a.MoneyCost, a.ReqSkillLine, a.ReqSkillRank, a.Reqlevel, a.Index FROM npc_trainer AS a " - "INNER JOIN npc_trainer AS b ON a.ID = -(b.SpellID) " - "UNION SELECT * FROM npc_trainer WHERE SpellID > 0"); + } while (trainersResult->NextRow()); + } - if (!result) + for (auto const& unusedSpells : spellsByTrainer) { - TC_LOG_ERROR("server.loading", ">> Loaded 0 Trainers. DB table `npc_trainer` is empty!"); - - return; + for (Trainer::Spell const& unusedSpell : unusedSpells.second) + { + TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing trainer (TrainerId: %u) for SpellId %u, ignoring", unusedSpells.first, unusedSpell.SpellId); + } } - uint32 count = 0; - - do + if (QueryResult trainerLocalesResult = WorldDatabase.Query("SELECT Id, locale, Greeting_lang FROM trainer_locale")) { - Field* fields = result->Fetch(); + do + { + Field* fields = trainerLocalesResult->Fetch(); + uint32 trainerId = fields[0].GetUInt32(); + std::string localeName = fields[1].GetString(); - uint32 ID = fields[0].GetUInt32(); - uint32 SpellID = fields[1].GetUInt32(); - uint32 MoneyCost = fields[2].GetUInt32(); - uint32 ReqSkillLine = fields[3].GetUInt16(); - uint32 ReqSkillRank = fields[4].GetUInt16(); - uint32 ReqLevel = fields[5].GetUInt8(); - uint32 Index = fields[6].GetUInt8(); + LocaleConstant locale = GetLocaleByName(localeName); + if (locale == LOCALE_enUS) + continue; - AddSpellToTrainer(ID, SpellID, MoneyCost, ReqSkillLine, ReqSkillRank, ReqLevel, Index); + if (Trainer::Trainer* trainer = Trinity::Containers::MapGetValuePtr(_trainers, trainerId)) + trainer->AddGreetingLocale(locale, fields[2].GetString()); + else + TC_LOG_ERROR("sql.sql", "Table `trainer_locale` references non-existing trainer (TrainerId: %u) for locale %s, ignoring", + trainerId, localeName.c_str()); - ++count; + } while (trainerLocalesResult->NextRow()); } - while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %d Trainers in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Trainers in %u ms", _trainers.size(), GetMSTimeDiffToNow(oldMSTime)); } int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, uint8 referenceType, std::set<uint32> *skip_vendors) @@ -8748,9 +8732,19 @@ void ObjectMgr::LoadGossipMenuItems() _gossipMenuItemsStore.clear(); QueryResult result = WorldDatabase.Query( - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - "SELECT menu_id, id, option_icon, option_text, OptionBroadcastTextID, option_id, npc_option_npcflag, action_menu_id, action_poi_id, box_coded, box_money, box_text, BoxBroadcastTextID " - "FROM gossip_menu_option ORDER BY menu_id, id"); + // 0 1 2 3 4 5 6 + "SELECT o.MenuId, o.OptionIndex, o.OptionIcon, o.OptionText, o.OptionBroadcastTextId, o.OptionType, o.OptionNpcflag, " + // 7 8 + "oa.ActionMenuId, oa.ActionPoiId, " + // 9 10 11 12 + "ob.BoxCoded, ob.BoxMoney, ob.BoxText, ob.BoxBroadcastTextId, " + // 13 + "ot.TrainerId " + "FROM gossip_menu_option o " + "LEFT JOIN gossip_menu_option_action oa ON o.MenuId = oa.MenuId AND o.OptionIndex = oa.OptionIndex " + "LEFT JOIN gossip_menu_option_box ob ON o.MenuId = ob.MenuId AND o.OptionIndex = ob.OptionIndex " + "LEFT JOIN gossip_menu_option_trainer ot ON o.MenuId = ot.MenuId AND o.OptionIndex = ot.OptionIndex " + "ORDER BY o.MenuId, o.OptionIndex"); if (!result) { @@ -8766,12 +8760,12 @@ void ObjectMgr::LoadGossipMenuItems() GossipMenuItems gMenuItem; - gMenuItem.MenuId = fields[0].GetUInt16(); - gMenuItem.OptionIndex = fields[1].GetUInt16(); - gMenuItem.OptionIcon = fields[2].GetUInt32(); + gMenuItem.MenuId = fields[0].GetUInt32(); + gMenuItem.OptionIndex = fields[1].GetUInt32(); + gMenuItem.OptionIcon = fields[2].GetUInt8(); gMenuItem.OptionText = fields[3].GetString(); gMenuItem.OptionBroadcastTextId = fields[4].GetUInt32(); - gMenuItem.OptionType = fields[5].GetUInt8(); + gMenuItem.OptionType = fields[5].GetUInt32(); gMenuItem.OptionNpcflag = fields[6].GetUInt64(); gMenuItem.ActionMenuId = fields[7].GetUInt32(); gMenuItem.ActionPoiId = fields[8].GetUInt32(); @@ -8779,10 +8773,11 @@ void ObjectMgr::LoadGossipMenuItems() gMenuItem.BoxMoney = fields[10].GetUInt32(); gMenuItem.BoxText = fields[11].GetString(); gMenuItem.BoxBroadcastTextId = fields[12].GetUInt32(); + gMenuItem.TrainerId = fields[13].GetUInt32(); if (gMenuItem.OptionIcon >= GOSSIP_ICON_MAX) { - TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for menu %u, id %u has unknown icon id %u. Replacing with GOSSIP_ICON_CHAT", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.OptionIcon); + TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for MenuId %u, OptionIndex %u has unknown icon id %u. Replacing with GOSSIP_ICON_CHAT", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.OptionIcon); gMenuItem.OptionIcon = GOSSIP_ICON_CHAT; } @@ -8790,17 +8785,17 @@ void ObjectMgr::LoadGossipMenuItems() { if (!sBroadcastTextStore.LookupEntry(gMenuItem.OptionBroadcastTextId)) { - TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for menu %u, id %u has non-existing or incompatible OptionBroadcastTextId %u, ignoring.", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.OptionBroadcastTextId); + TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for MenuId %u, OptionIndex %u has non-existing or incompatible OptionBroadcastTextId %u, ignoring.", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.OptionBroadcastTextId); gMenuItem.OptionBroadcastTextId = 0; } } if (gMenuItem.OptionType >= GOSSIP_OPTION_MAX) - TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.OptionType); + TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for MenuId %u, OptionIndex %u has unknown option id %u. Option will not be used", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.OptionType); if (gMenuItem.ActionPoiId && !GetPointOfInterest(gMenuItem.ActionPoiId)) { - TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for menu %u, id %u use non-existing action_poi_id %u, ignoring", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.ActionPoiId); + TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for MenuId %u, OptionIndex %u use non-existing action_poi_id %u, ignoring", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.ActionPoiId); gMenuItem.ActionPoiId = 0; } @@ -8808,11 +8803,17 @@ void ObjectMgr::LoadGossipMenuItems() { if (!sBroadcastTextStore.LookupEntry(gMenuItem.BoxBroadcastTextId)) { - TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for menu %u, id %u has non-existing or incompatible BoxBroadcastTextId %u, ignoring.", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.BoxBroadcastTextId); + TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option` for MenuId %u, OptionIndex %u has non-existing or incompatible BoxBroadcastTextId %u, ignoring.", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.BoxBroadcastTextId); gMenuItem.BoxBroadcastTextId = 0; } } + if (gMenuItem.TrainerId && !GetTrainer(gMenuItem.TrainerId)) + { + TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option_trainer` for MenuId %u, OptionIndex %u use non-existing TrainerId %u, ignoring", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.TrainerId); + gMenuItem.TrainerId = 0; + } + _gossipMenuItemsStore.insert(GossipMenuItemsContainer::value_type(gMenuItem.MenuId, gMenuItem)); ++count; } @@ -8821,6 +8822,11 @@ void ObjectMgr::LoadGossipMenuItems() TC_LOG_INFO("server.loading", ">> Loaded %u gossip_menu_option entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +Trainer::Trainer const* ObjectMgr::GetTrainer(uint32 trainerId) const +{ + return Trinity::Containers::MapGetValuePtr(_trainers, trainerId); +} + void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, uint8 type, bool persist /*= true*/) { VendorItemData& vList = _cacheVendorItemStore[entry]; |