diff options
18 files changed, 194 insertions, 104 deletions
diff --git a/sql/updates/world/master/9999_99_99_00_world.sql b/sql/updates/world/master/9999_99_99_00_world.sql new file mode 100644 index 00000000000..7287d23d45b --- /dev/null +++ b/sql/updates/world/master/9999_99_99_00_world.sql @@ -0,0 +1,12 @@ +-- +DROP TABLE IF EXISTS `creature_template_gossip`; +CREATE TABLE `creature_template_gossip` ( + `CreatureID` int UNSIGNED NOT NULL, + `MenuID` int UNSIGNED NOT NULL, + `VerifiedBuild` int NOT NULL DEFAULT 0, + PRIMARY KEY (`CreatureID`, `MenuID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT INTO `creature_template_gossip` SELECT `entry`, `gossip_menu_id`, `VerifiedBuild` FROM `creature_template` WHERE `gossip_menu_id` <> 0; + +ALTER TABLE `creature_template` DROP COLUMN `gossip_menu_id`; diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 251789d8cfb..b53e2738911 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -77,7 +77,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 4f80e811e03..125610378fd 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1530,12 +1530,10 @@ bool ConditionMgr::addToGossipMenus(Condition* cond) const { for (GossipMenusContainer::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr) { - if ((*itr).second.MenuID == cond->SourceGroup && (*itr).second.TextID == uint32(cond->SourceEntry)) - { - (*itr).second.Conditions.push_back(cond); - return true; - } + if (itr->second.MenuID == cond->SourceGroup && (itr->second.TextID == uint32(cond->SourceEntry) || cond->SourceEntry == 0)) + itr->second.Conditions.push_back(cond); } + return true; } TC_LOG_ERROR("sql.sql", "{} GossipMenu {} not found.", cond->ToString(), cond->SourceGroup); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 038aa5e2bb0..5210e4be33e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -294,7 +294,7 @@ Creature::Creature(bool isWorldObject) : Unit(isWorldObject), MapObject(), m_Pla m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(UI64LIT(0)), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_cannotReachTarget(false), m_cannotReachTimer(0), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _lastDamagedTime(0), - _regenerateHealth(true), _isMissingCanSwimFlagOutOfCombat(false) + _regenerateHealth(true), _isMissingCanSwimFlagOutOfCombat(false), _gossipMenuId(0) { m_regenTimer = CREATURE_REGEN_INTERVAL; @@ -3525,13 +3525,10 @@ void Creature::ExitVehicle(Position const* /*exitPosition*/) uint32 Creature::GetGossipMenuId() const { - if (_gossipMenuId) - return *_gossipMenuId; - - return GetCreatureTemplate()->GossipMenuId; + return _gossipMenuId; } -void Creature::SetGossipMenuId(Optional<uint32> gossipMenuId) +void Creature::SetGossipMenuId(uint32 gossipMenuId) { _gossipMenuId = gossipMenuId; } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index c5ea0be20e9..c77feb358e9 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -413,7 +413,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma bool HasFlag(CreatureStaticFlags8 flag) const { return _staticFlags.HasFlag(flag); } uint32 GetGossipMenuId() const; - void SetGossipMenuId(Optional<uint32> gossipMenuId); + void SetGossipMenuId(uint32 gossipMenuId); uint32 GetTrainerId() const; void SetTrainerId(Optional<uint32> trainerId); @@ -507,7 +507,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma bool _isMissingCanSwimFlagOutOfCombat; - Optional<uint32> _gossipMenuId; + uint32 _gossipMenuId; Optional<uint32> _trainerId; }; diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 851fcaac76b..b147c2ad04b 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -478,7 +478,7 @@ struct TC_GAME_API CreatureTemplate std::string SubName; std::string TitleAlt; std::string IconName; - uint32 GossipMenuId; + std::vector<uint32> GossipMenuIds; std::unordered_map<Difficulty, CreatureLevelScaling> scalingStore; int32 HealthScalingExpansion; uint32 RequiredExpansion; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9037c15c88b..bba11970aa1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14233,7 +14233,7 @@ uint32 Player::GetGossipTextId(WorldObject* source) if (!source) return DEFAULT_GOSSIP_MESSAGE; - return GetGossipTextId(GetDefaultGossipMenuForSource(source), source); + return GetGossipTextId(GetGossipMenuForSource(source), source); } uint32 Player::GetGossipTextId(uint32 menuId, WorldObject* source) @@ -14247,6 +14247,10 @@ uint32 Player::GetGossipTextId(uint32 menuId, WorldObject* source) for (GossipMenusContainer::const_iterator itr = menuBounds.first; itr != menuBounds.second; ++itr) { + // continue if only checks menuid instead of text + if (!itr->second.TextID) + continue; + if (sConditionMgr->IsObjectMeetToConditions(this, source, itr->second.Conditions)) textId = itr->second.TextID; } @@ -14254,12 +14258,33 @@ uint32 Player::GetGossipTextId(uint32 menuId, WorldObject* source) return textId; } -uint32 Player::GetDefaultGossipMenuForSource(WorldObject* source) +uint32 Player::GetGossipMenuForSource(WorldObject* source) { switch (source->GetTypeId()) { case TYPEID_UNIT: - return source->ToCreature()->GetGossipMenuId(); + { + uint32 menuIdToShow = source->ToCreature()->GetGossipMenuId(); + + // if menu id is set by script + if (menuIdToShow) + return menuIdToShow; + + // otherwise pick from db based on conditions + for (uint32 menuId : source->ToCreature()->GetCreatureTemplate()->GossipMenuIds) + { + GossipMenusMapBounds menuBounds = sObjectMgr->GetGossipMenusMapBounds(menuId); + + for (GossipMenusContainer::const_iterator itr = menuBounds.first; itr != menuBounds.second; ++itr) + { + if (!sConditionMgr->IsObjectMeetToConditions(this, source, itr->second.Conditions)) + continue; + + menuIdToShow = menuId; + } + } + return menuIdToShow; + } case TYPEID_GAMEOBJECT: return source->ToGameObject()->GetGOInfo()->GetGossipMenuId(); default: diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index c4e6bce850c..76862cfd9e6 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1542,7 +1542,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> uint32 GetGossipTextId(uint32 menuId, WorldObject* source); uint32 GetGossipTextId(WorldObject* source); - static uint32 GetDefaultGossipMenuForSource(WorldObject* source); + uint32 GetGossipMenuForSource(WorldObject* source); /*********************************************************/ /*** QUEST SYSTEM ***/ diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 209f08a92ab..f75365fe390 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -352,21 +352,21 @@ void ObjectMgr::LoadCreatureTemplates() // 0 1 2 3 4 5 6 7 8 // "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, " - // 9 10 11 12 13 14 - // "TitleAlt, IconName, gossip_menu_id, HealthScalingExpansion, RequiredExpansion, VignetteID, " - // 15 16 17 18 19 20 21 22 23 24 25 + // 9 10 11 12 13 + // "TitleAlt, IconName, HealthScalingExpansion, RequiredExpansion, VignetteID, " + // 14 15 16 17 18 19 20 21 22 23 24 // "faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, " - // 26 27 28 29 30 31 32 33 + // 25 26 27 28 29 30 31 32 // "unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, " - // 34 35 36 37 38 39 40 41 42 43 + // 33 34 35 36 37 38 39 40 41 42 // "type_flags, type_flags2, lootid, pickpocketloot, skinloot, VehicleId, mingold, maxgold, AIName, MovementType, " - // 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 + // 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 // "ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, " - // 59 60 61 62 63 64 + // 58 59 60 61 62 63 // "RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, " - // 65 66 67 + // 64 65 66 // "mechanic_immune_mask, spell_school_immune_mask, flags_extra, " - // 68 69 + // 67 68 // "ScriptName, StringId FROM creature_template WHERE entry = ? OR 1 = ?"); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE); @@ -420,34 +420,33 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.SubName = fields[8].GetString(); creatureTemplate.TitleAlt = fields[9].GetString(); creatureTemplate.IconName = fields[10].GetString(); - creatureTemplate.GossipMenuId = fields[11].GetUInt32(); - creatureTemplate.HealthScalingExpansion = fields[12].GetInt32(); - creatureTemplate.RequiredExpansion = fields[13].GetUInt32(); - creatureTemplate.VignetteID = fields[14].GetUInt32(); - creatureTemplate.faction = fields[15].GetUInt16(); - creatureTemplate.npcflag = fields[16].GetUInt64(); - creatureTemplate.speed_walk = fields[17].GetFloat(); - creatureTemplate.speed_run = fields[18].GetFloat(); - creatureTemplate.scale = fields[19].GetFloat(); - creatureTemplate.rank = uint32(fields[20].GetUInt8()); - creatureTemplate.dmgschool = uint32(fields[21].GetInt8()); - creatureTemplate.BaseAttackTime = fields[22].GetUInt32(); - creatureTemplate.RangeAttackTime = fields[23].GetUInt32(); - creatureTemplate.BaseVariance = fields[24].GetFloat(); - creatureTemplate.RangeVariance = fields[25].GetFloat(); - creatureTemplate.unit_class = uint32(fields[26].GetUInt8()); - creatureTemplate.unit_flags = fields[27].GetUInt32(); - creatureTemplate.unit_flags2 = fields[28].GetUInt32(); - creatureTemplate.unit_flags3 = fields[29].GetUInt32(); - creatureTemplate.dynamicflags = fields[30].GetUInt32(); - creatureTemplate.family = CreatureFamily(fields[31].GetInt32()); - creatureTemplate.trainer_class = uint32(fields[32].GetUInt8()); - creatureTemplate.type = uint32(fields[33].GetUInt8()); - creatureTemplate.type_flags = fields[34].GetUInt32(); - creatureTemplate.type_flags2 = fields[35].GetUInt32(); - creatureTemplate.lootid = fields[36].GetUInt32(); - creatureTemplate.pickpocketLootId = fields[37].GetUInt32(); - creatureTemplate.SkinLootId = fields[38].GetUInt32(); + creatureTemplate.HealthScalingExpansion = fields[11].GetInt32(); + creatureTemplate.RequiredExpansion = fields[12].GetUInt32(); + creatureTemplate.VignetteID = fields[13].GetUInt32(); + creatureTemplate.faction = fields[14].GetUInt16(); + creatureTemplate.npcflag = fields[15].GetUInt64(); + creatureTemplate.speed_walk = fields[16].GetFloat(); + creatureTemplate.speed_run = fields[17].GetFloat(); + creatureTemplate.scale = fields[18].GetFloat(); + creatureTemplate.rank = uint32(fields[19].GetUInt8()); + creatureTemplate.dmgschool = uint32(fields[20].GetInt8()); + creatureTemplate.BaseAttackTime = fields[21].GetUInt32(); + creatureTemplate.RangeAttackTime = fields[22].GetUInt32(); + creatureTemplate.BaseVariance = fields[23].GetFloat(); + creatureTemplate.RangeVariance = fields[24].GetFloat(); + creatureTemplate.unit_class = uint32(fields[25].GetUInt8()); + creatureTemplate.unit_flags = fields[26].GetUInt32(); + creatureTemplate.unit_flags2 = fields[27].GetUInt32(); + creatureTemplate.unit_flags3 = fields[28].GetUInt32(); + creatureTemplate.dynamicflags = fields[29].GetUInt32(); + creatureTemplate.family = CreatureFamily(fields[30].GetInt32()); + creatureTemplate.trainer_class = uint32(fields[31].GetUInt8()); + creatureTemplate.type = uint32(fields[32].GetUInt8()); + creatureTemplate.type_flags = fields[33].GetUInt32(); + creatureTemplate.type_flags2 = 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] = 0; @@ -455,51 +454,97 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i) creatureTemplate.spells[i] = 0; - creatureTemplate.VehicleId = fields[39].GetUInt32(); - creatureTemplate.mingold = fields[40].GetUInt32(); - creatureTemplate.maxgold = fields[41].GetUInt32(); - creatureTemplate.AIName = fields[42].GetString(); - creatureTemplate.MovementType = uint32(fields[43].GetUInt8()); + creatureTemplate.VehicleId = fields[38].GetUInt32(); + creatureTemplate.mingold = fields[39].GetUInt32(); + creatureTemplate.maxgold = fields[40].GetUInt32(); + creatureTemplate.AIName = fields[41].GetString(); + creatureTemplate.MovementType = uint32(fields[42].GetUInt8()); + if (!fields[43].IsNull()) + creatureTemplate.Movement.Ground = static_cast<CreatureGroundMovementType>(fields[43].GetUInt8()); + if (!fields[44].IsNull()) - creatureTemplate.Movement.Ground = static_cast<CreatureGroundMovementType>(fields[44].GetUInt8()); + creatureTemplate.Movement.Swim = fields[44].GetBool(); if (!fields[45].IsNull()) - creatureTemplate.Movement.Swim = fields[45].GetBool(); + creatureTemplate.Movement.Flight = static_cast<CreatureFlightMovementType>(fields[45].GetUInt8()); if (!fields[46].IsNull()) - creatureTemplate.Movement.Flight = static_cast<CreatureFlightMovementType>(fields[46].GetUInt8()); + creatureTemplate.Movement.Rooted = fields[46].GetBool(); if (!fields[47].IsNull()) - creatureTemplate.Movement.Rooted = fields[47].GetBool(); + creatureTemplate.Movement.Chase = static_cast<CreatureChaseMovementType>(fields[47].GetUInt8()); if (!fields[48].IsNull()) - creatureTemplate.Movement.Chase = static_cast<CreatureChaseMovementType>(fields[48].GetUInt8()); + creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[48].GetUInt8()); if (!fields[49].IsNull()) - creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[49].GetUInt8()); - - if (!fields[50].IsNull()) - creatureTemplate.Movement.InteractionPauseTimer = fields[50].GetUInt32(); - - creatureTemplate.HoverHeight = fields[51].GetFloat(); - creatureTemplate.ModHealth = fields[52].GetFloat(); - creatureTemplate.ModHealthExtra = fields[53].GetFloat(); - creatureTemplate.ModMana = fields[54].GetFloat(); - creatureTemplate.ModManaExtra = fields[55].GetFloat(); - creatureTemplate.ModArmor = fields[56].GetFloat(); - creatureTemplate.ModDamage = fields[57].GetFloat(); - creatureTemplate.ModExperience = fields[58].GetFloat(); - creatureTemplate.RacialLeader = fields[59].GetBool(); - creatureTemplate.movementId = fields[60].GetUInt32(); - creatureTemplate.CreatureDifficultyID = fields[61].GetInt32(); - creatureTemplate.WidgetSetID = fields[62].GetInt32(); - creatureTemplate.WidgetSetUnitConditionID = fields[63].GetInt32(); - creatureTemplate.RegenHealth = fields[64].GetBool(); - creatureTemplate.MechanicImmuneMask = fields[65].GetUInt64(); - creatureTemplate.SpellSchoolImmuneMask = fields[66].GetUInt32(); - creatureTemplate.flags_extra = fields[67].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[68].GetString()); - creatureTemplate.StringId = fields[69].GetString(); + creatureTemplate.Movement.InteractionPauseTimer = fields[49].GetUInt32(); + + creatureTemplate.HoverHeight = fields[50].GetFloat(); + creatureTemplate.ModHealth = fields[51].GetFloat(); + creatureTemplate.ModHealthExtra = fields[52].GetFloat(); + creatureTemplate.ModMana = fields[53].GetFloat(); + creatureTemplate.ModManaExtra = fields[54].GetFloat(); + creatureTemplate.ModArmor = fields[55].GetFloat(); + creatureTemplate.ModDamage = fields[56].GetFloat(); + creatureTemplate.ModExperience = fields[57].GetFloat(); + creatureTemplate.RacialLeader = fields[58].GetBool(); + creatureTemplate.movementId = fields[59].GetUInt32(); + creatureTemplate.CreatureDifficultyID = fields[60].GetInt32(); + creatureTemplate.WidgetSetID = fields[61].GetInt32(); + creatureTemplate.WidgetSetUnitConditionID = fields[62].GetInt32(); + creatureTemplate.RegenHealth = fields[63].GetBool(); + creatureTemplate.MechanicImmuneMask = fields[64].GetUInt64(); + creatureTemplate.SpellSchoolImmuneMask = fields[65].GetUInt32(); + creatureTemplate.flags_extra = fields[66].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[67].GetString()); + creatureTemplate.StringId = fields[68].GetString(); +} + +void ObjectMgr::LoadCreatureTemplateGossip() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT CreatureID, MenuID FROM creature_template_gossip"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 creature template gossip definitions. DB table `creature_template_gossip` is empty."); + return; + } + + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + + uint32 creatureID = fields[0].GetUInt32(); + uint32 menuID = fields[1].GetUInt32(); + + CreatureTemplateContainer::iterator itr = _creatureTemplateStore.find(creatureID); + if (itr == _creatureTemplateStore.end()) + { + TC_LOG_ERROR("sql.sql", "creature_template_gossip has gossip definitions for creature %u but this creature doesn't exist", creatureID); + continue; + } + + GossipMenusMapBounds menuBounds = sObjectMgr->GetGossipMenusMapBounds(menuID); + if (menuBounds.first == menuBounds.second) + { + TC_LOG_ERROR("sql.sql", "creature_template_gossip has gossip definitions for menu id %u but this menu doesn't exist", menuID); + continue; + } + + CreatureTemplate& creatureTemplate = itr->second; + creatureTemplate.GossipMenuIds.push_back(menuID); + + ++count; + + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u creature template gossip menus in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadCreatureTemplateResistances() @@ -1243,9 +1288,9 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->ModDamage *= Creature::_GetDamageMod(cInfo->rank); - if (cInfo->GossipMenuId && !(cInfo->npcflag & UNIT_NPC_FLAG_GOSSIP)) - TC_LOG_INFO("sql.sql", "Creature (Entry: {}) has assigned gossip menu {}, but npcflag does not include UNIT_NPC_FLAG_GOSSIP.", cInfo->Entry, cInfo->GossipMenuId); - else if (!cInfo->GossipMenuId && cInfo->npcflag & UNIT_NPC_FLAG_GOSSIP) + if (!cInfo->GossipMenuIds.empty() && !(cInfo->npcflag & UNIT_NPC_FLAG_GOSSIP)) + TC_LOG_INFO("sql.sql", "Creature (Entry: {}) has assigned gossip menu, but npcflag does not include UNIT_NPC_FLAG_GOSSIP.", cInfo->Entry); + else if (cInfo->GossipMenuIds.empty() && cInfo->npcflag & UNIT_NPC_FLAG_GOSSIP) TC_LOG_INFO("sql.sql", "Creature (Entry: {}) has npcflag UNIT_NPC_FLAG_GOSSIP, but gossip menu is unassigned.", cInfo->Entry); } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index e397b035994..cb81f9903ad 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1326,6 +1326,7 @@ class TC_GAME_API ObjectMgr void LoadCreatureTemplates(); void LoadCreatureTemplateAddons(); void LoadCreatureTemplate(Field* fields); + void LoadCreatureTemplateGossip(); void LoadCreatureTemplateResistances(); void LoadCreatureTemplateSpells(); void LoadCreatureTemplateModels(); diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index a2274a3b6e0..23249272a41 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -183,7 +183,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet) if (!unit->AI()->OnGossipHello(_player)) { // _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); - _player->PrepareGossipMenu(unit, unit->GetGossipMenuId(), true); + _player->PrepareGossipMenu(unit, _player->GetGossipMenuForSource(unit), true); _player->SendPreparedGossip(unit); } } diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 18eb7daa947..aa80e11e1cd 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -98,7 +98,7 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPackets::Quest::QuestGiverHe if (creature->AI()->OnGossipHello(_player)) return; - _player->PrepareGossipMenu(creature, creature->GetGossipMenuId(), true); + _player->PrepareGossipMenu(creature, _player->GetGossipMenuForSource(creature), true); _player->SendPreparedGossip(creature); } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index b5a73e3feeb..0f4cde86499 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2256,6 +2256,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Gossip menu addon..."); sObjectMgr->LoadGossipMenuAddon(); + TC_LOG_INFO("server.loading", "Loading Creature Template Gossip..."); + sObjectMgr->LoadCreatureTemplateGossip(); + TC_LOG_INFO("server.loading", "Loading Creature trainers..."); sObjectMgr->LoadCreatureTrainers(); // must be after LoadGossipMenuItems diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index ac65e640ade..67f23cf43ba 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -678,7 +678,7 @@ public: bool OnGossipHello(Player* player) override { - uint32 gossipMenuId = Player::GetDefaultGossipMenuForSource(me); + uint32 gossipMenuId = player->GetGossipMenuForSource(me); InitGossipMenuFor(player, gossipMenuId); if (player->GetQuestStatus(QUEST_DEATH_CHALLENGE) == QUEST_STATUS_INCOMPLETE && me->IsFullHealth()) { @@ -688,7 +688,7 @@ public: if (player->IsInCombat() || me->IsInCombat()) return true; - AddGossipItemFor(player, gossipMenuId, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + AddGossipItemFor(player, player->GetGossipMenuForSource(me), 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID()); } return true; diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp index 4f6dfe7f7d7..992163dfa3a 100644 --- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp +++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp @@ -130,7 +130,7 @@ public: bool OnGossipHello(Player* player) override { - uint32 gossipMenuId = Player::GetDefaultGossipMenuForSource(me); + uint32 gossipMenuId = player->GetGossipMenuForSource(me); InitGossipMenuFor(player, gossipMenuId); if (instance->GetData(TYPE_FREE_NPC) != DONE && instance->GetData(TYPE_RETHILGORE) == DONE) AddGossipItemFor(player, gossipMenuId, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp index c520cdd56d7..4041d02be1e 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp @@ -69,7 +69,9 @@ enum Points enum Misc { - ITEM_VIRTUAL_ITEM = 5301 + ITEM_VIRTUAL_ITEM = 5301, + + GOSSIP_MENU_START_INTRO = 12797, }; Position const VoljinIntroWaypoint[4] = @@ -104,7 +106,7 @@ class npc_voljin_zulaman : public CreatureScript if (_instance->GetData(DATA_ZULAMAN_STATE) != NOT_STARTED) return true; - if (me->GetGossipMenuId() == menuId && !gossipListId) + if (menuId == GOSSIP_MENU_START_INTRO && !gossipListId) { _events.Reset(); me->SetMountDisplayId(0); diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp index 9258359eb16..b9fcfc779c4 100644 --- a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp +++ b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp @@ -104,6 +104,11 @@ enum Points MAX_BRANN_WAYPOINTS_INTRO = 17 }; +enum GossipMenuIds +{ + GOSSIP_MENU_START_INTRO = 11339, +}; + Position const AnraphetActivatePos = {-193.656f, 366.689f, 75.91001f, 3.138207f}; Position const BrannIntroWaypoint[MAX_BRANN_WAYPOINTS_INTRO] = @@ -331,12 +336,12 @@ class npc_brann_bronzebeard_anraphet : public CreatureScript { npc_brann_bronzebeard_anraphetAI(Creature* creature) : CreatureAI(creature), _currentPoint(0), _instance(creature->GetInstanceScript()) { } - bool OnGossipSelect(Player* /*player*/, uint32 sender, uint32 action) override + bool OnGossipSelect(Player* /*player*/, uint32 menuId, uint32 action) override { if (_instance->GetBossState(DATA_VAULT_OF_LIGHTS) == DONE) return true; - if (me->GetGossipMenuId() == sender && !action) + if (menuId == GOSSIP_MENU_START_INTRO && !action) { _instance->SetBossState(DATA_VAULT_OF_LIGHTS, IN_PROGRESS); _currentPoint = 0; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index eadbf4252cb..cbff6530c4f 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -364,7 +364,9 @@ enum MiscData enum Misc { DATA_PLAGUE_STACK = 70337, - DATA_VILE = 45814622 + DATA_VILE = 45814622, + + GOSSIP_MENU_START_INTRO = 10993 }; class NecroticPlagueTargetCheck @@ -1193,7 +1195,7 @@ struct npc_tirion_fordring_tft : public ScriptedAI bool OnGossipSelect(Player* /*player*/, uint32 menuId, uint32 gossipListId) override { - if (me->GetGossipMenuId() == menuId && !gossipListId) + if (menuId == GOSSIP_MENU_START_INTRO && !gossipListId) { _events.SetPhase(PHASE_INTRO); me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); |