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.cpp340
1 files changed, 167 insertions, 173 deletions
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 80f823f9beb..ff0bc2938c0 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -367,15 +367,13 @@ void ObjectMgr::LoadCreatureTemplates()
"modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, "
// 21 22 23 24 25 26 27 28 29 30
"scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, "
- // 31 32 33 34 35 36 37
- "dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, "
- // 38 39 40 41 42 43 44 45 46 47 48
- "type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, "
- // 49 50 51 52 53 54 55 56 57 58 59 60 61
- "spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
- // 62 63 64 65 66 67 68 69 70
+ // 31 32 33 34 35 36 37 38 39 40 41 42 43
+ "dynamicflags, family, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, "
+ // 44 45 46 47 48 49 50 51 52 53 54 55 56 57
+ "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
+ // 58 59 60 61 62 63 64 65 66
"ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, DamageModifier, "
- // 71 72 73 74 75 76 77 78
+ // 67 68 69 70 71 72 73 74
"ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName "
"FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId");
@@ -439,54 +437,50 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields)
creatureTemplate.unit_flags2 = fields[30].GetUInt32();
creatureTemplate.dynamicflags = fields[31].GetUInt32();
creatureTemplate.family = CreatureFamily(fields[32].GetUInt8());
- creatureTemplate.trainer_type = fields[33].GetUInt8();
- creatureTemplate.trainer_spell = fields[34].GetUInt32();
- creatureTemplate.trainer_class = fields[35].GetUInt8();
- creatureTemplate.trainer_race = fields[36].GetUInt8();
- creatureTemplate.type = fields[37].GetUInt8();
- creatureTemplate.type_flags = fields[38].GetUInt32();
- creatureTemplate.lootid = fields[39].GetUInt32();
- creatureTemplate.pickpocketLootId = fields[40].GetUInt32();
- creatureTemplate.SkinLootId = fields[41].GetUInt32();
+ creatureTemplate.type = fields[33].GetUInt8();
+ creatureTemplate.type_flags = fields[34].GetUInt32();
+ creatureTemplate.lootid = fields[35].GetUInt32();
+ creatureTemplate.pickpocketLootId = fields[36].GetUInt32();
+ creatureTemplate.SkinLootId = fields[37].GetUInt32();
for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
- creatureTemplate.resistance[i] = fields[42 + i - 1].GetInt16();
+ creatureTemplate.resistance[i] = fields[38 + i - 1].GetInt16();
for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
- creatureTemplate.spells[i] = fields[48 + i].GetUInt32();
-
- creatureTemplate.PetSpellDataId = fields[56].GetUInt32();
- creatureTemplate.VehicleId = fields[57].GetUInt32();
- creatureTemplate.mingold = fields[58].GetUInt32();
- creatureTemplate.maxgold = fields[59].GetUInt32();
- creatureTemplate.AIName = fields[60].GetString();
- creatureTemplate.MovementType = fields[61].GetUInt8();
- if (!fields[62].IsNull())
- creatureTemplate.Movement.Ground = static_cast<CreatureGroundMovementType>(fields[62].GetUInt8());
-
- if (!fields[63].IsNull())
- creatureTemplate.Movement.Swim = fields[63].GetBool();
-
- if (!fields[64].IsNull())
- creatureTemplate.Movement.Flight = static_cast<CreatureFlightMovementType>(fields[64].GetUInt8());
-
- if (!fields[65].IsNull())
- creatureTemplate.Movement.Rooted = fields[65].GetBool();
-
- creatureTemplate.HoverHeight = fields[66].GetFloat();
- creatureTemplate.ModHealth = fields[67].GetFloat();
- creatureTemplate.ModMana = 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.SpellSchoolImmuneMask = fields[76].GetUInt32();
- creatureTemplate.flags_extra = fields[77].GetUInt32();
- creatureTemplate.ScriptID = GetScriptId(fields[78].GetString());
+ creatureTemplate.spells[i] = fields[44 + i].GetUInt32();
+
+ creatureTemplate.PetSpellDataId = fields[52].GetUInt32();
+ creatureTemplate.VehicleId = fields[53].GetUInt32();
+ creatureTemplate.mingold = fields[54].GetUInt32();
+ creatureTemplate.maxgold = fields[55].GetUInt32();
+ creatureTemplate.AIName = fields[56].GetString();
+ creatureTemplate.MovementType = fields[57].GetUInt8();
+ if (!fields[58].IsNull())
+ creatureTemplate.Movement.Ground = static_cast<CreatureGroundMovementType>(fields[58].GetUInt8());
+
+ if (!fields[59].IsNull())
+ creatureTemplate.Movement.Swim = fields[59].GetBool();
+
+ if (!fields[60].IsNull())
+ creatureTemplate.Movement.Flight = static_cast<CreatureFlightMovementType>(fields[60].GetUInt8());
+
+ if (!fields[61].IsNull())
+ creatureTemplate.Movement.Rooted = fields[61].GetBool();
+
+ creatureTemplate.HoverHeight = fields[62].GetFloat();
+ creatureTemplate.ModHealth = fields[63].GetFloat();
+ creatureTemplate.ModMana = fields[64].GetFloat();
+ creatureTemplate.ModArmor = fields[65].GetFloat();
+ creatureTemplate.ModDamage = fields[66].GetFloat();
+ creatureTemplate.ModExperience = fields[67].GetFloat();
+ creatureTemplate.RacialLeader = fields[68].GetBool();
+
+ creatureTemplate.movementId = fields[69].GetUInt32();
+ creatureTemplate.RegenHealth = fields[70].GetBool();
+ creatureTemplate.MechanicImmuneMask = fields[71].GetUInt32();
+ creatureTemplate.SpellSchoolImmuneMask = fields[72].GetUInt32();
+ creatureTemplate.flags_extra = fields[73].GetUInt32();
+ creatureTemplate.ScriptID = GetScriptId(fields[74].GetString());
}
void ObjectMgr::LoadCreatureTemplateAddons()
@@ -687,39 +681,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
cInfo->family, cInfo->DifficultyEntry[diff]);
}
- if (cInfo->trainer_class != difficultyInfo->trainer_class)
- {
- TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, trainer_class: %u) has different `trainer_class` in difficulty %u mode (Entry: %u, trainer_class: %u).",
- cInfo->Entry, cInfo->trainer_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->trainer_class);
- TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `trainer_class`=%u WHERE `entry`=%u;",
- cInfo->trainer_class, cInfo->DifficultyEntry[diff]);
- 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->trainer_spell != difficultyInfo->trainer_spell)
- {
- TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, 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).",
@@ -912,9 +873,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);
@@ -8702,122 +8660,149 @@ 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)
+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 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 SpellID (%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 SpellID (%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;
+ }
- if (GetTalentSpellCost(SpellID))
- {
- TC_LOG_ERROR("sql.sql", "Table `npc_trainer` contains an ID (%u) for a non-existing SpellID (%u) which is a talent, ignoring", ID, SpellID);
- return;
- }
+ if (GetTalentSpellCost(spell.SpellId))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing spell (SpellId: %u) which is a talent, 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;
+ 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, trainerId, spell.SpellId);
+ allReqValid = false;
+ }
+ }
+
+ if (!allReqValid)
+ continue;
- if (!trainerSpell.ReqLevel)
- trainerSpell.ReqLevel = spellinfo->SpellLevel;
+ spellsByTrainer[trainerId].push_back(spell);
+ } while (trainerSpellsResult->NextRow());
+ }
- // calculate learned spell for profession case when stored cast-spell
- trainerSpell.ReqAbility[0] = SpellID;
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (QueryResult trainersResult = WorldDatabase.Query("SELECT Id, Type, Requirement, Greeting FROM trainer"))
{
- if (spellinfo->Effects[i].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 (spellinfo->Effects[i].TargetA.GetTarget() != 0 && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_TARGET_ALLY
- && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_TARGET_ANY && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_CASTER)
+ do
{
- 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;
- }
+ Field* fields = trainersResult->Fetch();
+
+ uint32 trainerId = fields[0].GetUInt32();
+ Trainer::Type trainerType = Trainer::Type(fields[1].GetUInt8());
+ uint32 requirement = fields[2].GetUInt32();
+ std::string greeting = fields[3].GetString();
+ std::vector<Trainer::Spell> spells;
+ auto spellsItr = spellsByTrainer.find(trainerId);
+ if (spellsItr != spellsByTrainer.end())
+ {
+ spells = std::move(spellsItr->second);
+ spellsByTrainer.erase(spellsItr);
+ }
- trainerSpell.ReqAbility[i] = spellinfo->Effects[i].TriggerSpell;
+ _trainers.emplace(std::piecewise_construct, std::forward_as_tuple(trainerId), std::forward_as_tuple(trainerId, trainerType, requirement, std::move(greeting), std::move(spells)));
+ } while (trainersResult->NextRow());
+ }
- if (trainerSpell.ReqAbility[i])
+ for (auto const& unusedSpells : spellsByTrainer)
+ {
+ for (Trainer::Spell const& unusedSpell : unusedSpells.second)
{
- SpellInfo const* learnedSpellInfo = sSpellMgr->GetSpellInfo(trainerSpell.ReqAbility[i]);
- if (learnedSpellInfo && learnedSpellInfo->IsProfession())
- data.trainerType = 2;
+ TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing trainer (TrainerId: %u) for SpellId %u, ignoring", unusedSpells.first, unusedSpell.SpellId);
}
}
- return;
-}
-
-void ObjectMgr::LoadTrainerSpell()
-{
- uint32 oldMSTime = getMSTime();
+ if (QueryResult trainerLocalesResult = WorldDatabase.Query("SELECT Id, locale, Greeting_lang FROM trainer_locale"))
+ {
+ do
+ {
+ Field* fields = trainerLocalesResult->Fetch();
+ uint32 trainerId = fields[0].GetUInt32();
+ std::string localeName = fields[1].GetString();
- // For reload case
- _cacheTrainerSpellStore.clear();
+ LocaleConstant locale = GetLocaleByName(localeName);
+ if (locale == LOCALE_enUS)
+ continue;
- QueryResult result = WorldDatabase.Query("SELECT b.ID, a.SpellID, a.MoneyCost, a.ReqSkillLine, a.ReqSkillRank, a.ReqLevel FROM npc_trainer AS a "
- "INNER JOIN npc_trainer AS b ON a.ID = -(b.SpellID) "
- "UNION SELECT * FROM npc_trainer WHERE SpellID > 0");
+ 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());
+ } while (trainerLocalesResult->NextRow());
+ }
- if (!result)
- {
- TC_LOG_ERROR("sql.sql", ">> Loaded 0 Trainers. DB table `npc_trainer` is empty!");
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Trainers in %u ms", _trainers.size(), GetMSTimeDiffToNow(oldMSTime));
+}
- return;
- }
+void ObjectMgr::LoadCreatureDefaultTrainers()
+{
+ uint32 oldMSTime = getMSTime();
- uint32 count = 0;
+ _creatureDefaultTrainers.clear();
- do
+ if (QueryResult result = WorldDatabase.Query("SELECT CreatureId, TrainerId FROM creature_default_trainer"))
{
- Field* fields = result->Fetch();
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 creatureId = fields[0].GetUInt32();
+ uint32 trainerId = fields[1].GetUInt32();
- 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();
+ if (!GetCreatureTemplate(creatureId))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `creature_default_trainer` references non-existing creature template (CreatureId: %u), ignoring", creatureId);
+ continue;
+ }
- AddSpellToTrainer(ID, SpellID, MoneyCost, ReqSkillLine, ReqSkillRank, ReqLevel);
+ _creatureDefaultTrainers[creatureId] = trainerId;
- ++count;
+ } while (result->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 " default trainers in %u ms", _creatureDefaultTrainers.size(), GetMSTimeDiffToNow(oldMSTime));
}
uint32 ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, std::set<uint32>* skip_vendors)
@@ -9022,6 +9007,15 @@ void ObjectMgr::LoadGossipMenuItems()
TC_LOG_INFO("server.loading", ">> Loaded %u gossip_menu_option entries in %u ms", uint32(_gossipMenuItemsStore.size()), GetMSTimeDiffToNow(oldMSTime));
}
+Trainer::Trainer const* ObjectMgr::GetTrainer(uint32 creatureId) const
+{
+ auto itr = _creatureDefaultTrainers.find(creatureId);
+ if (itr != _creatureDefaultTrainers.end())
+ return Trinity::Containers::MapGetValuePtr(_trainers, itr->second);
+
+ return nullptr;
+}
+
void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, bool persist /*= true*/)
{
VendorItemData& vList = _cacheVendorItemStore[entry];