aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Globals/ObjectMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Globals/ObjectMgr.cpp')
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp324
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];