diff options
Diffstat (limited to 'src/server/game/Globals/ObjectMgr.cpp')
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 541 |
1 files changed, 263 insertions, 278 deletions
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 2dd2753cde3..d0b70bf3d8a 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -54,6 +54,7 @@ #include "VMapFactory.h" #include "World.h" #include <G3D/g3dmath.h> +#include <numeric> ScriptMapMap sSpellScripts; ScriptMapMap sEventScripts; @@ -171,30 +172,37 @@ ExtendedPlayerName ExtractExtendedPlayerName(std::string const& name) LanguageDesc lang_description[LANGUAGES_COUNT] = { - { LANG_ADDON, 0, 0 }, - { LANG_UNIVERSAL, 0, 0 }, - { LANG_ORCISH, 669, SKILL_LANG_ORCISH }, - { LANG_DARNASSIAN, 671, SKILL_LANG_DARNASSIAN }, - { LANG_TAURAHE, 670, SKILL_LANG_TAURAHE }, - { LANG_DWARVISH, 672, SKILL_LANG_DWARVEN }, - { LANG_COMMON, 668, SKILL_LANG_COMMON }, - { LANG_DEMONIC, 815, SKILL_LANG_DEMON_TONGUE }, - { LANG_TITAN, 816, SKILL_LANG_TITAN }, - { LANG_THALASSIAN, 813, SKILL_LANG_THALASSIAN }, - { LANG_DRACONIC, 814, SKILL_LANG_DRACONIC }, - { LANG_KALIMAG, 817, SKILL_LANG_OLD_TONGUE }, - { LANG_GNOMISH, 7340, SKILL_LANG_GNOMISH }, - { LANG_TROLL, 7341, SKILL_LANG_TROLL }, - { LANG_GUTTERSPEAK, 17737, SKILL_LANG_FORSAKEN }, - { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI }, - { LANG_ZOMBIE, 0, 0 }, - { LANG_GNOMISH_BINARY, 0, 0 }, - { LANG_GOBLIN_BINARY, 0, 0 }, - { LANG_WORGEN, 69270, SKILL_LANG_GILNEAN }, - { LANG_GOBLIN, 69269, SKILL_LANG_GOBLIN }, - { LANG_PANDAREN_NEUTRAL, 108127, SKILL_LANG_PANDAREN_NEUTRAL }, - { LANG_PANDAREN_ALLIANCE, 108130, SKILL_LANG_PANDAREN_ALLIANCE }, - { LANG_PANDAREN_HORDE, 108131, SKILL_LANG_PANDAREN_HORDE } + { LANG_ADDON, 0, 0 }, + { LANG_ADDON_LOGGED, 0, 0 }, + { LANG_UNIVERSAL, 0, 0 }, + { LANG_ORCISH, 669, SKILL_LANGUAGE_ORCISH }, + { LANG_DARNASSIAN, 671, SKILL_LANGUAGE_DARNASSIAN }, + { LANG_TAURAHE, 670, SKILL_LANGUAGE_TAURAHE }, + { LANG_DWARVISH, 672, SKILL_LANGUAGE_DWARVEN }, + { LANG_COMMON, 668, SKILL_LANGUAGE_COMMON }, + { LANG_DEMONIC, 815, SKILL_LANGUAGE_DEMON_TONGUE }, + { LANG_TITAN, 816, SKILL_LANGUAGE_TITAN }, + { LANG_THALASSIAN, 813, SKILL_LANGUAGE_THALASSIAN }, + { LANG_DRACONIC, 814, SKILL_LANGUAGE_DRACONIC }, + { LANG_KALIMAG, 265462, SKILL_LANGUAGE_OLD_TONGUE }, + { LANG_GNOMISH, 7340, SKILL_LANGUAGE_GNOMISH }, + { LANG_TROLL, 7341, SKILL_LANGUAGE_TROLL }, + { LANG_GUTTERSPEAK, 17737, SKILL_LANGUAGE_FORSAKEN }, + { LANG_DRAENEI, 29932, SKILL_LANGUAGE_DRAENEI }, + { LANG_ZOMBIE, 265467, 0 }, + { LANG_GNOMISH_BINARY, 265460, 0 }, + { LANG_GOBLIN_BINARY, 265461, 0 }, + { LANG_WORGEN, 69270, SKILL_LANGUAGE_GILNEAN }, + { LANG_GOBLIN, 69269, SKILL_LANGUAGE_GOBLIN }, + { LANG_PANDAREN_NEUTRAL, 108127, SKILL_LANGUAGE_PANDAREN_NEUTRAL }, + { LANG_PANDAREN_ALLIANCE, 108130, 0 }, + { LANG_PANDAREN_HORDE, 108131, 0 }, + { LANG_SPRITE, 265466, 0 }, + { LANG_SHATH_YAR, 265465, 0 }, + { LANG_NERGLISH, 265464, 0 }, + { LANG_MOONKIN, 265463, 0 }, + { LANG_SHALASSIAN, 262439, SKILL_LANGUAGE_SHALASSIAN }, + { LANG_THALASSIAN_2, 262454, SKILL_LANGUAGE_THALASSIAN_2 } }; LanguageDesc const* GetLanguageDescByID(uint32 lang) @@ -404,21 +412,21 @@ void ObjectMgr::LoadCreatureTemplates() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 8 - QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, " - // 9 10 11 12 13 14 15 16 17 18 19 20 - "modelid4, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, " - // 21 22 23 24 25 26 27 28 29 30 31 + // 0 1 2 3 4 5 6 7 8 + QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, " + // 9 10 11 12 13 14 15 16 + "TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, " + // 17 18 19 20 21 22 23 24 25 26 27 "faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, " - // 32 33 34 35 36 37 38 39 + // 28 29 30 31 32 33 34 35 "unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, " - // 40 41 42 43 44 45 46 47 48 49 50 + // 36 37 38 39 40 41 42 43 44 45 46 "type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, " - // 51 52 53 54 55 56 57 58 59 60 61 62 63 + // 47 48 49 50 51 52 53 54 55 56 57 58 59 "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, " - // 64 65 66 67 68 69 70 71 72 + // 60 61 62 63 64 65 66 67 68 "InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, " - // 73 74 75 76 77 78 + // 69 70 71 72 73 74 "RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template"); if (!result) @@ -435,6 +443,9 @@ void ObjectMgr::LoadCreatureTemplates() } while (result->NextRow()); + // We load the creature models after loading but before checking + LoadCreatureTemplateModels(); + // Checking needs to be done after loading because of the difficulty self referencing for (CreatureTemplateContainer::const_iterator itr = _creatureTemplateStore.begin(); itr != _creatureTemplateStore.end(); ++itr) CheckCreatureTemplate(&itr->second); @@ -456,72 +467,121 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i) creatureTemplate.KillCredit[i] = fields[4 + i].GetUInt32(); - creatureTemplate.Modelid1 = fields[6].GetUInt32(); - creatureTemplate.Modelid2 = fields[7].GetUInt32(); - creatureTemplate.Modelid3 = fields[8].GetUInt32(); - creatureTemplate.Modelid4 = fields[9].GetUInt32(); - creatureTemplate.Name = fields[10].GetString(); - creatureTemplate.FemaleName = fields[11].GetString(); - creatureTemplate.SubName = fields[12].GetString(); - creatureTemplate.TitleAlt = fields[13].GetString(); - creatureTemplate.IconName = fields[14].GetString(); - creatureTemplate.GossipMenuId = fields[15].GetUInt32(); - creatureTemplate.minlevel = fields[16].GetInt16(); - creatureTemplate.maxlevel = fields[17].GetInt16(); - creatureTemplate.HealthScalingExpansion = fields[18].GetInt32(); - creatureTemplate.RequiredExpansion = fields[19].GetUInt32(); - creatureTemplate.VignetteID = fields[20].GetUInt32(); - creatureTemplate.faction = fields[21].GetUInt16(); - creatureTemplate.npcflag = fields[22].GetUInt64(); - creatureTemplate.speed_walk = fields[23].GetFloat(); - creatureTemplate.speed_run = fields[24].GetFloat(); - creatureTemplate.scale = fields[25].GetFloat(); - creatureTemplate.rank = uint32(fields[26].GetUInt8()); - creatureTemplate.dmgschool = uint32(fields[27].GetInt8()); - creatureTemplate.BaseAttackTime = fields[28].GetUInt32(); - creatureTemplate.RangeAttackTime = fields[29].GetUInt32(); - creatureTemplate.BaseVariance = fields[30].GetFloat(); - creatureTemplate.RangeVariance = fields[31].GetFloat(); - creatureTemplate.unit_class = uint32(fields[32].GetUInt8()); - creatureTemplate.unit_flags = fields[33].GetUInt32(); - creatureTemplate.unit_flags2 = fields[34].GetUInt32(); - creatureTemplate.unit_flags3 = fields[35].GetUInt32(); - creatureTemplate.dynamicflags = fields[36].GetUInt32(); - creatureTemplate.family = CreatureFamily(fields[37].GetUInt8()); - creatureTemplate.trainer_class = uint32(fields[38].GetUInt8()); - creatureTemplate.type = uint32(fields[39].GetUInt8()); - creatureTemplate.type_flags = fields[40].GetUInt32(); - creatureTemplate.type_flags2 = fields[41].GetUInt32(); - creatureTemplate.lootid = fields[42].GetUInt32(); - creatureTemplate.pickpocketLootId = fields[43].GetUInt32(); - creatureTemplate.SkinLootId = fields[44].GetUInt32(); + creatureTemplate.Name = fields[6].GetString(); + creatureTemplate.FemaleName = fields[7].GetString(); + creatureTemplate.SubName = fields[8].GetString(); + creatureTemplate.TitleAlt = fields[9].GetString(); + creatureTemplate.IconName = fields[10].GetString(); + creatureTemplate.GossipMenuId = fields[11].GetUInt32(); + creatureTemplate.minlevel = fields[12].GetInt16(); + creatureTemplate.maxlevel = fields[13].GetInt16(); + creatureTemplate.HealthScalingExpansion = fields[14].GetInt32(); + creatureTemplate.RequiredExpansion = fields[15].GetUInt32(); + creatureTemplate.VignetteID = fields[16].GetUInt32(); + creatureTemplate.faction = fields[17].GetUInt16(); + creatureTemplate.npcflag = fields[18].GetUInt64(); + creatureTemplate.speed_walk = fields[19].GetFloat(); + creatureTemplate.speed_run = fields[20].GetFloat(); + creatureTemplate.scale = fields[21].GetFloat(); + creatureTemplate.rank = uint32(fields[22].GetUInt8()); + creatureTemplate.dmgschool = uint32(fields[23].GetInt8()); + creatureTemplate.BaseAttackTime = fields[24].GetUInt32(); + creatureTemplate.RangeAttackTime = fields[25].GetUInt32(); + creatureTemplate.BaseVariance = fields[26].GetFloat(); + creatureTemplate.RangeVariance = fields[27].GetFloat(); + creatureTemplate.unit_class = uint32(fields[28].GetUInt8()); + creatureTemplate.unit_flags = fields[29].GetUInt32(); + creatureTemplate.unit_flags2 = fields[30].GetUInt32(); + creatureTemplate.unit_flags3 = fields[31].GetUInt32(); + creatureTemplate.dynamicflags = fields[32].GetUInt32(); + creatureTemplate.family = CreatureFamily(fields[33].GetUInt8()); + creatureTemplate.trainer_class = uint32(fields[34].GetUInt8()); + creatureTemplate.type = uint32(fields[35].GetUInt8()); + creatureTemplate.type_flags = fields[36].GetUInt32(); + creatureTemplate.type_flags2 = fields[37].GetUInt32(); + creatureTemplate.lootid = fields[38].GetUInt32(); + creatureTemplate.pickpocketLootId = fields[39].GetUInt32(); + creatureTemplate.SkinLootId = fields[40].GetUInt32(); for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - creatureTemplate.resistance[i] = fields[45 + i - 1].GetInt16(); + creatureTemplate.resistance[i] = fields[41 + i - 1].GetInt16(); for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i) - creatureTemplate.spells[i] = fields[51 + i].GetUInt32(); - - creatureTemplate.VehicleId = fields[59].GetUInt32(); - creatureTemplate.mingold = fields[60].GetUInt32(); - creatureTemplate.maxgold = fields[61].GetUInt32(); - creatureTemplate.AIName = fields[62].GetString(); - creatureTemplate.MovementType = uint32(fields[63].GetUInt8()); - creatureTemplate.InhabitType = uint32(fields[64].GetUInt8()); - creatureTemplate.HoverHeight = fields[65].GetFloat(); - creatureTemplate.ModHealth = fields[66].GetFloat(); - creatureTemplate.ModHealthExtra = fields[67].GetFloat(); - creatureTemplate.ModMana = fields[68].GetFloat(); - creatureTemplate.ModManaExtra = fields[69].GetFloat(); - creatureTemplate.ModArmor = fields[70].GetFloat(); - creatureTemplate.ModDamage = fields[71].GetFloat(); - creatureTemplate.ModExperience = fields[72].GetFloat(); - creatureTemplate.RacialLeader = fields[73].GetBool(); - creatureTemplate.movementId = fields[74].GetUInt32(); - creatureTemplate.RegenHealth = fields[75].GetBool(); - creatureTemplate.MechanicImmuneMask = fields[76].GetUInt32(); - creatureTemplate.flags_extra = fields[77].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[78].GetString()); + creatureTemplate.spells[i] = fields[47 + i].GetUInt32(); + + creatureTemplate.VehicleId = fields[55].GetUInt32(); + creatureTemplate.mingold = fields[56].GetUInt32(); + creatureTemplate.maxgold = fields[57].GetUInt32(); + creatureTemplate.AIName = fields[58].GetString(); + creatureTemplate.MovementType = uint32(fields[59].GetUInt8()); + creatureTemplate.InhabitType = uint32(fields[60].GetUInt8()); + creatureTemplate.HoverHeight = fields[61].GetFloat(); + creatureTemplate.ModHealth = fields[62].GetFloat(); + creatureTemplate.ModHealthExtra = fields[63].GetFloat(); + creatureTemplate.ModMana = fields[64].GetFloat(); + creatureTemplate.ModManaExtra = fields[65].GetFloat(); + creatureTemplate.ModArmor = fields[66].GetFloat(); + creatureTemplate.ModDamage = fields[67].GetFloat(); + creatureTemplate.ModExperience = fields[68].GetFloat(); + creatureTemplate.RacialLeader = fields[69].GetBool(); + creatureTemplate.movementId = fields[70].GetUInt32(); + creatureTemplate.RegenHealth = fields[71].GetBool(); + creatureTemplate.MechanicImmuneMask = fields[72].GetUInt32(); + creatureTemplate.flags_extra = fields[73].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[74].GetString()); +} + +void ObjectMgr::LoadCreatureTemplateModels() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 2 3 + QueryResult result = WorldDatabase.Query("SELECT CreatureID, CreatureDisplayID, DisplayScale, Probability FROM creature_template_model ORDER BY Idx ASC"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 creature template model definitions. DB table `creature_template_model` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 creatureId = fields[0].GetUInt32(); + uint32 creatureDisplayId = fields[1].GetUInt32(); + float displayScale = fields[2].GetFloat(); + float probability = fields[3].GetFloat(); + + CreatureTemplate const* cInfo = GetCreatureTemplate(creatureId); + if (!cInfo) + { + TC_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_template_model`", creatureId); + continue; + } + + CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(creatureDisplayId); + if (!displayEntry) + { + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing CreatureDisplayID id (%u), this can crash the client.", creatureId, creatureDisplayId); + continue; + } + + CreatureModelInfo const* modelInfo = GetCreatureModelInfo(creatureDisplayId); + if (!modelInfo) + TC_LOG_ERROR("sql.sql", "No model data exist for `CreatureDisplayID` = %u listed by creature (Entry: %u).", creatureDisplayId, creatureId); + + if (displayScale <= 0.0f) + displayScale = 1.0f; + + const_cast<CreatureTemplate*>(cInfo)->Models.emplace_back(creatureDisplayId, displayScale, probability); + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u creature template models in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadCreatureTemplateAddons() @@ -860,76 +920,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->faction = sFactionTemplateStore.AssertEntry(35)->ID; // this might seem stupid but all shit will would break if faction 35 did not exist } - // used later for scale - CreatureDisplayInfoEntry const* displayScaleEntry = nullptr; - - if (cInfo->Modelid1) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1); - if (!displayEntry) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid1 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid1); - const_cast<CreatureTemplate*>(cInfo)->Modelid1 = 0; - } - else - displayScaleEntry = displayEntry; - - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid1); - if (!modelInfo) - TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid1` = %u listed by creature (Entry: %u).", cInfo->Modelid1, cInfo->Entry); - } - - if (cInfo->Modelid2) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2); - if (!displayEntry) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid2 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid2); - const_cast<CreatureTemplate*>(cInfo)->Modelid2 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid2); - if (!modelInfo) - TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid2` = %u listed by creature (Entry: %u).", cInfo->Modelid2, cInfo->Entry); - } - - if (cInfo->Modelid3) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3); - if (!displayEntry) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid3 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid3); - const_cast<CreatureTemplate*>(cInfo)->Modelid3 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid3); - if (!modelInfo) - TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid3` = %u listed by creature (Entry: %u).", cInfo->Modelid3, cInfo->Entry); - } - - if (cInfo->Modelid4) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4); - if (!displayEntry) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid4 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid4); - const_cast<CreatureTemplate*>(cInfo)->Modelid4 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid4); - if (!modelInfo) - TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid4` = %u listed by creature (Entry: %u).", cInfo->Modelid4, cInfo->Entry); - } - - if (!displayScaleEntry) - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) does not have any existing display id in Modelid1/Modelid2/Modelid3/Modelid4.", cInfo->Entry); - for (uint8 k = 0; k < MAX_KILL_CREDIT; ++k) { if (cInfo->KillCredit[k]) @@ -942,6 +932,11 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) } } + if (!cInfo->Models.size()) + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) does not have any existing display id in creature_template_model.", cInfo->Entry); + else if (std::accumulate(cInfo->Models.begin(), cInfo->Models.end(), 0.0f, [](float sum, CreatureModel const& model) { return sum + model.Probability; }) <= 0.0f) + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has zero total chance for all models in creature_template_model.", cInfo->Entry); + if (!cInfo->unit_class || ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid unit_class (%u) in creature_template. Set to 1 (UNIT_CLASS_WARRIOR).", cInfo->Entry, cInfo->unit_class); @@ -1022,15 +1017,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->MovementType = IDLE_MOTION_TYPE; } - /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc - if (cInfo->scale <= 0.0f) - { - if (displayScaleEntry) - const_cast<CreatureTemplate*>(cInfo)->scale = displayScaleEntry->CreatureModelScale; - else - const_cast<CreatureTemplate*>(cInfo)->scale = 1.0f; - } - if (cInfo->HealthScalingExpansion < EXPANSION_LEVEL_CURRENT || cInfo->HealthScalingExpansion > (MAX_EXPANSIONS - 1)) { TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (ID: %u) with invalid `HealthScalingExpansion` %i. Ignored and set to 0.", cInfo->Entry, cInfo->HealthScalingExpansion); @@ -1402,14 +1388,16 @@ CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelId) const return nullptr; } -uint32 ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data /*= nullptr*/) +CreatureModel const* ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data /*= nullptr*/) { // Load creature model (display id) if (data && data->displayid) - return data->displayid; + if (CreatureModel const* model = cinfo->GetModelWithDisplayId(data->displayid)) + return model; if (!(cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)) - return cinfo->GetRandomValidModelId(); + if (CreatureModel const* model = cinfo->GetRandomValidModel()) + return model; // Triggers by default receive the invisible model return cinfo->GetFirstInvisibleModel(); @@ -1442,9 +1430,9 @@ void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64& npcFl } } -CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32* displayID) const +CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(CreatureModel* model, CreatureTemplate const* creatureTemplate) const { - CreatureModelInfo const* modelInfo = GetCreatureModelInfo(*displayID); + CreatureModelInfo const* modelInfo = GetCreatureModelInfo(model->CreatureDisplayID); if (!modelInfo) return nullptr; @@ -1453,11 +1441,20 @@ CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32* display { CreatureModelInfo const* minfo_tmp = GetCreatureModelInfo(modelInfo->displayId_other_gender); if (!minfo_tmp) - TC_LOG_ERROR("sql.sql", "Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", *displayID, modelInfo->displayId_other_gender); + TC_LOG_ERROR("sql.sql", "Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", model->CreatureDisplayID, modelInfo->displayId_other_gender); else { // DisplayID changed - *displayID = modelInfo->displayId_other_gender; + model->CreatureDisplayID = modelInfo->displayId_other_gender; + if (creatureTemplate) + { + auto itr = std::find_if(creatureTemplate->Models.begin(), creatureTemplate->Models.end(), [&](CreatureModel const& templateModel) + { + return templateModel.CreatureDisplayID == modelInfo->displayId_other_gender; + }); + if (itr != creatureTemplate->Models.end()) + *model = *itr; + } return minfo_tmp; } } @@ -3492,13 +3489,13 @@ void ObjectMgr::LoadPlayerInfo() do { Field* fields = result->Fetch(); - uint32 raceMask = fields[0].GetUInt32(); + uint64 raceMask = fields[0].GetUInt64(); uint32 classMask = fields[1].GetUInt32(); uint32 spellId = fields[2].GetUInt32(); if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_spell_custom` table, ignoring.", raceMask); + TC_LOG_ERROR("sql.sql", "Wrong race mask " UI64FMTD " in `playercreateinfo_spell_custom` table, ignoring.", raceMask); continue; } @@ -3510,7 +3507,7 @@ void ObjectMgr::LoadPlayerInfo() for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex) { - if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask)) + if (raceMask == 0 || ((UI64LIT(1) << (raceIndex - 1)) & raceMask)) { for (uint32 classIndex = CLASS_WARRIOR; classIndex < MAX_CLASSES; ++classIndex) { @@ -3552,13 +3549,13 @@ void ObjectMgr::LoadPlayerInfo() do { Field* fields = result->Fetch(); - uint32 raceMask = fields[0].GetUInt32(); + uint64 raceMask = fields[0].GetUInt64(); uint32 classMask = fields[1].GetUInt32(); uint32 spellId = fields[2].GetUInt32(); if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_cast_spell` table, ignoring.", raceMask); + TC_LOG_ERROR("sql.sql", "Wrong race mask " UI64FMTD " in `playercreateinfo_cast_spell` table, ignoring.", raceMask); continue; } @@ -3570,7 +3567,7 @@ void ObjectMgr::LoadPlayerInfo() for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex) { - if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask)) + if (raceMask == 0 || ((UI64LIT(1) << (raceIndex - 1)) & raceMask)) { for (uint32 classIndex = CLASS_WARRIOR; classIndex < MAX_CLASSES; ++classIndex) { @@ -3924,35 +3921,35 @@ void ObjectMgr::LoadQuests() mExclusiveQuestGroups.clear(); QueryResult result = WorldDatabase.Query("SELECT " - //0 1 2 3 4 5 6 7 8 9 10 11 - "ID, QuestType, QuestLevel, MaxScalingLevel, QuestPackageID, MinLevel, QuestSortID, QuestInfoID, SuggestedGroupNum, RewardNextQuest, RewardXPDifficulty, RewardXPMultiplier, " - //12 13 14 15 16 17 18 19 20 21 22 + //0 1 2 3 4 5 6 7 8 9 10 11 12 + "ID, QuestType, QuestLevel, ScalingFactionGroup, MaxScalingLevel, QuestPackageID, MinLevel, QuestSortID, QuestInfoID, SuggestedGroupNum, RewardNextQuest, RewardXPDifficulty, RewardXPMultiplier, " + //13 14 15 16 17 18 19 20 21 22 23 "RewardMoney, RewardMoneyDifficulty, RewardMoneyMultiplier, RewardBonusMoney, RewardDisplaySpell1, RewardDisplaySpell2, RewardDisplaySpell3, RewardSpell, RewardHonor, RewardKillHonor, StartItem, " - //23 24 25 26 27 - "RewardArtifactXPDifficulty, RewardArtifactXPMultiplier, RewardArtifactCategoryID, Flags, FlagsEx, " - //28 29 30 31 32 33 34 35 + //24 25 26 27 28 29 + "RewardArtifactXPDifficulty, RewardArtifactXPMultiplier, RewardArtifactCategoryID, Flags, FlagsEx, FlagsEx2, " + //30 31 32 33 34 35 36 37 "RewardItem1, RewardAmount1, ItemDrop1, ItemDropQuantity1, RewardItem2, RewardAmount2, ItemDrop2, ItemDropQuantity2, " - //36 37 38 39 40 41 42 43 + //38 39 40 41 42 43 44 45 "RewardItem3, RewardAmount3, ItemDrop3, ItemDropQuantity3, RewardItem4, RewardAmount4, ItemDrop4, ItemDropQuantity4, " - //44 45 46 47 48 49 + //46 47 48 49 50 51 "RewardChoiceItemID1, RewardChoiceItemQuantity1, RewardChoiceItemDisplayID1, RewardChoiceItemID2, RewardChoiceItemQuantity2, RewardChoiceItemDisplayID2, " - //50 51 52 53 54 55 + //52 53 54 55 56 57 "RewardChoiceItemID3, RewardChoiceItemQuantity3, RewardChoiceItemDisplayID3, RewardChoiceItemID4, RewardChoiceItemQuantity4, RewardChoiceItemDisplayID4, " - //56 57 58 59 60 61 + //58 59 60 61 62 63 "RewardChoiceItemID5, RewardChoiceItemQuantity5, RewardChoiceItemDisplayID5, RewardChoiceItemID6, RewardChoiceItemQuantity6, RewardChoiceItemDisplayID6, " - //62 63 64 65 66 67 68 69 70 71 - "POIContinent, POIx, POIy, POIPriority, RewardTitle, RewardArenaPoints, RewardSkillLineID, RewardNumSkillUps, PortraitGiver, PortraitTurnIn, " - //72 73 74 75 76 77 78 79 + //64 65 66 67 68 69 70 71 72 73 74 + "POIContinent, POIx, POIy, POIPriority, RewardTitle, RewardArenaPoints, RewardSkillLineID, RewardNumSkillUps, PortraitGiver, PortraitGiverMount, PortraitTurnIn, " + //75 76 77 78 79 80 81 82 "RewardFactionID1, RewardFactionValue1, RewardFactionOverride1, RewardFactionCapIn1, RewardFactionID2, RewardFactionValue2, RewardFactionOverride2, RewardFactionCapIn2, " - //80 81 82 83 84 85 86 87 + //83 84 85 86 87 88 89 90 "RewardFactionID3, RewardFactionValue3, RewardFactionOverride3, RewardFactionCapIn3, RewardFactionID4, RewardFactionValue4, RewardFactionOverride4, RewardFactionCapIn4, " - //88 89 90 91 92 + //91 92 93 94 95 "RewardFactionID5, RewardFactionValue5, RewardFactionOverride5, RewardFactionCapIn5, RewardFactionFlags, " - //93 94 95 96 97 98 99 100 + //96 97 98 99 100 101 102 103 "RewardCurrencyID1, RewardCurrencyQty1, RewardCurrencyID2, RewardCurrencyQty2, RewardCurrencyID3, RewardCurrencyQty3, RewardCurrencyID4, RewardCurrencyQty4, " - //101 102 103 104 105 106 107 - "AcceptedSoundKitID, CompleteSoundKitID, AreaGroupID, TimeAllowed, AllowableRaces, QuestRewardID, Expansion, " - //108 109 110 111 112 113 114 115 116 + //104 105 106 107 108 109 110 + "AcceptedSoundKitID, CompleteSoundKitID, AreaGroupID, TimeAllowed, AllowableRaces, TreasurePickerID, Expansion, " + //111 112 113 114 115 116 117 118 119 "LogTitle, LogDescription, QuestDescription, AreaDescription, PortraitGiverText, PortraitGiverName, PortraitTurnInText, PortraitTurnInName, QuestCompletionLog" " FROM quest_template"); if (!result) @@ -6174,7 +6171,7 @@ uint32 ObjectMgr::GetNearestTaxiNode(float x, float y, float z, uint32 mapid, ui if (!node || node->ContinentID != mapid || !(node->Flags & requireFlag)) continue; - uint8 field = (uint8)((node->ID - 1) / 8); + uint32 field = uint32((node->ID - 1) / 8); uint32 submask = 1 << ((node->ID - 1) % 8); // skip not taxi network nodes @@ -6227,7 +6224,8 @@ void ObjectMgr::GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uin uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team /* = false */) { - uint32 mount_id = 0; + CreatureModel mountModel; + CreatureTemplate const* mount_info = nullptr; // select mount creature id TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id); @@ -6247,22 +6245,23 @@ uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt mount_entry = team == ALLIANCE ? node->MountCreatureID[0] : node->MountCreatureID[1]; } - CreatureTemplate const* mount_info = GetCreatureTemplate(mount_entry); + mount_info = GetCreatureTemplate(mount_entry); if (mount_info) { - mount_id = mount_info->GetRandomValidModelId(); - if (!mount_id) + CreatureModel const* model = mount_info->GetRandomValidModel(); + if (!model) { TC_LOG_ERROR("sql.sql", "No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry); return 0; } + mountModel = *model; } } // minfo is not actually used but the mount_id was updated - GetCreatureModelRandomGender(&mount_id); + GetCreatureModelRandomGender(&mountModel, mount_info); - return mount_id; + return mountModel.CreatureDisplayID; } void ObjectMgr::LoadGraveyardZones() @@ -7027,8 +7026,8 @@ void ObjectMgr::LoadGameObjectTemplate() "Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, " // 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 "Data13, Data14, Data15, Data16, Data17, Data18, Data19, Data20, Data21, Data22, Data23, Data24, Data25, Data26, Data27, Data28, " - // 37 38 39 40 41 42 43 - "Data29, Data30, Data31, Data32, RequiredLevel, AIName, ScriptName " + // 37 38 39 40 41 42 43 44 + "Data29, Data30, Data31, Data32, Data33, RequiredLevel, AIName, ScriptName " "FROM gameobject_template"); if (!result) @@ -7058,9 +7057,9 @@ void ObjectMgr::LoadGameObjectTemplate() for (uint8 i = 0; i < MAX_GAMEOBJECT_DATA; ++i) got.raw.data[i] = fields[8 + i].GetUInt32(); - got.RequiredLevel = fields[41].GetInt32(); - got.AIName = fields[42].GetString(); - got.ScriptId = GetScriptId(fields[43].GetString()); + got.RequiredLevel = fields[42].GetInt32(); + got.AIName = fields[43].GetString(); + got.ScriptId = GetScriptId(fields[44].GetString()); // Checks @@ -7696,8 +7695,8 @@ void ObjectMgr::LoadQuestPOI() uint32 count = 0; - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - QueryResult result = WorldDatabase.Query("SELECT QuestID, BlobIndex, Idx1, ObjectiveIndex, QuestObjectiveID, QuestObjectID, MapID, WorldMapAreaId, Floor, Priority, Flags, WorldEffectID, PlayerConditionID, WoDUnk1, AlwaysAllowMergingBlobs FROM quest_poi order by QuestID, Idx1"); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + QueryResult result = WorldDatabase.Query("SELECT QuestID, BlobIndex, Idx1, ObjectiveIndex, QuestObjectiveID, QuestObjectID, MapID, UiMapID, Priority, Flags, WorldEffectID, PlayerConditionID, SpawnTrackingID, AlwaysAllowMergingBlobs FROM quest_poi order by QuestID, Idx1"); if (!result) { TC_LOG_ERROR("server.loading", ">> Loaded 0 quest POI definitions. DB table `quest_poi` is empty."); @@ -7737,33 +7736,32 @@ void ObjectMgr::LoadQuestPOI() { Field* fields = result->Fetch(); - int32 QuestID = fields[0].GetInt32(); - int32 BlobIndex = fields[1].GetInt32(); - int32 Idx1 = fields[2].GetInt32(); - int32 ObjectiveIndex = fields[3].GetInt32(); - int32 QuestObjectiveID = fields[4].GetInt32(); - int32 QuestObjectID = fields[5].GetInt32(); - int32 MapID = fields[6].GetInt32(); - int32 WorldMapAreaId = fields[7].GetInt32(); - int32 Floor = fields[8].GetInt32(); - int32 Priority = fields[9].GetInt32(); - int32 Flags = fields[10].GetInt32(); - int32 WorldEffectID = fields[11].GetInt32(); - int32 PlayerConditionID = fields[12].GetInt32(); - int32 WoDUnk1 = fields[13].GetInt32(); - bool AlwaysAllowMergingBlobs = fields[14].GetBool(); - - if (!sObjectMgr->GetQuestTemplate(QuestID)) - TC_LOG_ERROR("sql.sql", "`quest_poi` quest id (%u) Idx1 (%u) does not exist in `quest_template`", QuestID, Idx1); - - QuestPOI POI(BlobIndex, ObjectiveIndex, QuestObjectiveID, QuestObjectID, MapID, WorldMapAreaId, Floor, Priority, Flags, WorldEffectID, PlayerConditionID, WoDUnk1, AlwaysAllowMergingBlobs); - if (QuestID < int32(POIs.size()) && Idx1 < int32(POIs[QuestID].size())) - { - POI.points = POIs[QuestID][Idx1]; - _questPOIStore[QuestID].push_back(POI); + int32 questID = fields[0].GetInt32(); + int32 blobIndex = fields[1].GetInt32(); + int32 idx1 = fields[2].GetInt32(); + int32 objectiveIndex = fields[3].GetInt32(); + int32 questObjectiveID = fields[4].GetInt32(); + int32 questObjectID = fields[5].GetInt32(); + int32 mapID = fields[6].GetInt32(); + int32 uiMapID = fields[7].GetInt32(); + int32 priority = fields[8].GetInt32(); + int32 flags = fields[9].GetInt32(); + int32 worldEffectID = fields[10].GetInt32(); + int32 playerConditionID = fields[11].GetInt32(); + int32 spawnTrackingID = fields[12].GetInt32(); + bool alwaysAllowMergingBlobs = fields[13].GetBool(); + + if (!sObjectMgr->GetQuestTemplate(questID)) + TC_LOG_ERROR("sql.sql", "`quest_poi` quest id (%u) Idx1 (%u) does not exist in `quest_template`", questID, idx1); + + QuestPOI POI(blobIndex, objectiveIndex, questObjectiveID, questObjectID, mapID, uiMapID, priority, flags, worldEffectID, playerConditionID, spawnTrackingID, alwaysAllowMergingBlobs); + if (questID < int32(POIs.size()) && idx1 < int32(POIs[questID].size())) + { + POI.points = POIs[questID][idx1]; + _questPOIStore[questID].push_back(POI); } else - TC_LOG_ERROR("sql.sql", "Table quest_poi references unknown quest points for quest %i POI id %i", QuestID, BlobIndex); + TC_LOG_ERROR("sql.sql", "Table quest_poi references unknown quest points for quest %i POI id %i", questID, blobIndex); ++count; } while (result->NextRow()); @@ -8578,7 +8576,7 @@ void ObjectMgr::LoadMailLevelRewards() Field* fields = result->Fetch(); uint8 level = fields[0].GetUInt8(); - uint32 raceMask = fields[1].GetUInt32(); + uint64 raceMask = fields[1].GetUInt64(); uint32 mailTemplateId = fields[2].GetUInt32(); uint32 senderEntry = fields[3].GetUInt32(); @@ -8590,7 +8588,7 @@ void ObjectMgr::LoadMailLevelRewards() if (!(raceMask & RACEMASK_ALL_PLAYABLE)) { - TC_LOG_ERROR("sql.sql", "Table `mail_level_reward` has raceMask (%u) for level %u that not include any player races, ignoring.", raceMask, level); + TC_LOG_ERROR("sql.sql", "Table `mail_level_reward` has raceMask (" UI64FMTD ") for level %u that not include any player races, ignoring.", raceMask, level); continue; } @@ -8669,18 +8667,6 @@ void ObjectMgr::LoadTrainers() if (!allReqValid) continue; - spell.LearnedSpellId = spell.SpellId; - for (SpellEffectInfo const* spellEffect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) - { - if (spellEffect && spellEffect->IsEffect(SPELL_EFFECT_LEARN_SPELL)) - { - ASSERT(spell.LearnedSpellId == spell.SpellId, - "Only one learned spell is currently supported - spell %u already teaches %u but it tried to overwrite it with %u", - spell.SpellId, spell.LearnedSpellId, spellEffect->TriggerSpell); - spell.LearnedSpellId = spellEffect->TriggerSpell; - } - } - spellsByTrainer[trainerId].push_back(spell); } while (trainerSpellsResult->NextRow()); @@ -9282,8 +9268,8 @@ CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unit void ObjectMgr::LoadCreatureClassLevelStats() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 8 9 10 11 - QueryResult result = WorldDatabase.Query("SELECT level, class, basemana, basearmor, attackpower, rangedattackpower, damage_base, damage_exp1, damage_exp2, damage_exp3, damage_exp4, damage_exp5 FROM creature_classlevelstats"); + // 0 1 2 3 4 5 + QueryResult result = WorldDatabase.Query("SELECT level, class, basemana, basearmor, attackpower, rangedattackpower FROM creature_classlevelstats"); if (!result) { @@ -9581,7 +9567,7 @@ void ObjectMgr::LoadTerrainWorldMaps() uint32 oldMSTime = getMSTime(); // 0 1 - QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`"); + QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, UiMapPhaseId FROM `terrain_worldmap`"); if (!result) { @@ -9595,7 +9581,7 @@ void ObjectMgr::LoadTerrainWorldMaps() Field* fields = result->Fetch(); uint32 mapId = fields[0].GetUInt32(); - uint32 worldMapArea = fields[1].GetUInt32(); + uint32 uiMapPhaseId = fields[1].GetUInt32(); if (!sMapStore.LookupEntry(mapId)) { @@ -9603,15 +9589,15 @@ void ObjectMgr::LoadTerrainWorldMaps() continue; } - if (!sWorldMapAreaStore.LookupEntry(worldMapArea)) + if (!sDB2Manager.IsUiMapPhase(uiMapPhaseId)) { - TC_LOG_ERROR("sql.sql", "WorldMapArea %u defined in `terrain_worldmap` does not exist, skipped.", worldMapArea); + TC_LOG_ERROR("sql.sql", "Phase %u defined in `terrain_worldmap` is not a valid terrain swap phase, skipped.", uiMapPhaseId); continue; } TerrainSwapInfo* terrainSwapInfo = &_terrainSwapInfoById[mapId]; terrainSwapInfo->Id = mapId; - terrainSwapInfo->UiWorldMapAreaIDSwaps.push_back(worldMapArea); + terrainSwapInfo->UiMapPhaseIDs.push_back(uiMapPhaseId); ++count; } while (result->NextRow()); @@ -9758,11 +9744,6 @@ TerrainSwapInfo const* ObjectMgr::GetTerrainSwapInfo(uint32 terrainSwapId) const return Trinity::Containers::MapGetValuePtr(_terrainSwapInfoById, terrainSwapId); } -std::vector<TerrainSwapInfo*> const* ObjectMgr::GetTerrainSwapsForMap(uint32 mapId) const -{ - return Trinity::Containers::MapGetValuePtr(_terrainSwapInfoByMap, mapId); -} - GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) const { GameObjectTemplateContainer::const_iterator itr = _gameObjectTemplateStore.find(entry); @@ -10104,7 +10085,7 @@ void ObjectMgr::LoadPlayerChoices() uint32 oldMSTime = getMSTime(); _playerChoices.clear(); - QueryResult choices = WorldDatabase.Query("SELECT ChoiceId, UiTextureKitId, Question, HideWarboardHeader FROM playerchoice"); + QueryResult choices = WorldDatabase.Query("SELECT ChoiceId, UiTextureKitId, Question, HideWarboardHeader, KeepOpenAfterChoice FROM playerchoice"); if (!choices) { @@ -10129,10 +10110,11 @@ void ObjectMgr::LoadPlayerChoices() choice.UiTextureKitId = fields[1].GetInt32(); choice.Question = fields[2].GetString(); choice.HideWarboardHeader = fields[3].GetBool(); + choice.KeepOpenAfterChoice = fields[4].GetBool(); } while (choices->NextRow()); - if (QueryResult responses = WorldDatabase.Query("SELECT ChoiceId, ResponseId, ChoiceArtFileId, Header, Answer, Description, Confirmation FROM playerchoice_response ORDER BY `Index` ASC")) + if (QueryResult responses = WorldDatabase.Query("SELECT ChoiceId, ResponseId, ChoiceArtFileId, Flags, WidgetSetID, GroupID, Header, Answer, Description, Confirmation FROM playerchoice_response ORDER BY `Index` ASC")) { do { @@ -10153,10 +10135,13 @@ void ObjectMgr::LoadPlayerChoices() PlayerChoiceResponse& response = choice->Responses.back(); response.ResponseId = responseId; response.ChoiceArtFileId = fields[2].GetInt32(); - response.Header = fields[3].GetString(); - response.Answer = fields[4].GetString(); - response.Description = fields[5].GetString(); - response.Confirmation = fields[6].GetString(); + response.Flags = fields[3].GetInt32(); + response.WidgetSetID = fields[4].GetUInt32(); + response.GroupID = fields[5].GetUInt8(); + response.Header = fields[6].GetString(); + response.Answer = fields[7].GetString(); + response.Description = fields[8].GetString(); + response.Confirmation = fields[9].GetString(); ++responseCount; } while (responses->NextRow()); |