diff options
Diffstat (limited to 'src/server/game/Globals/ObjectMgr.cpp')
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 340 |
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]; |