Core/Creature: Add support for multiple gossip menu IDs (#472)

* Core/Creature: Add support for multiple gossip menu IDs

Adds support for assigning multiple gossip menu IDs to creatures and
controlling them through conditions.

Cherry-picked and adapted from:
https://github.com/TrinityCore/TrinityCore/commit/36044a9470e9c39a71916e908ab6cf4f95677793

Also disables StormLib automatic static linking.

StormLib fix suggested by @brian8544 on Discord.

* merge prep

---------

Co-authored-by: Ovahlord <18347559+Ovahlord@users.noreply.github.com>
This commit is contained in:
seviandOvahlord authored and GitHub committed 2026-07-25 19:29:08 +02:00
1 parent 30aab19ce5
commit 9da95e6cc9
15 files changed
+199 -96

No files matched your search

@@ -0,0 +1,14 @@
--
CREATE TABLE `creature_template_gossip` (
`CreatureID` INT(10) UNSIGNED NOT NULL,
`MenuID` INT(10) UNSIGNED NOT NULL,
`VerifiedBuild` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`CreatureID`, `MenuID`) USING BTREE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;
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`;
@@ -76,7 +76,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, permission, help FROM command", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, exp_unk, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.HoverInitiallyEnabled, ctm.GravityInitiallyDisabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, minlevel, maxlevel, HealthScalingExpansion, exp_unk, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.HoverInitiallyEnabled, ctm.GravityInitiallyDisabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", 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);
+4 -5
View File
@@ -1401,12 +1401,11 @@ 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", "%s GossipMenu %u not found.", cond->ToString().c_str(), cond->SourceGroup);
+11 -1
View File
@@ -280,7 +280,7 @@ m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckT
m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), 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), _cyclicSplinePathId(0),
m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _lastDamagedTime(0), _isMissingSwimmingFlagOutOfCombat(false), _noNpcDamageBelowPctHealth(0.f)
m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _lastDamagedTime(0), _isMissingSwimmingFlagOutOfCombat(false), _noNpcDamageBelowPctHealth(0.f), _gossipMenuId(0)
{
m_valuesCount = UNIT_END;
@@ -1241,6 +1241,16 @@ Group* Creature::GetLootRecipientGroup() const
return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup);
}
uint32 Creature::GetGossipMenuId() const
{
return _gossipMenuId;
}
void Creature::SetGossipMenuId(uint32 gossipMenuID)
{
_gossipMenuId = gossipMenuID;
}
void Creature::SetLootRecipient(Unit* unit, bool withGroup)
{
// set the player whose group should receive the right
@@ -411,6 +411,9 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool HasStaticFlag(CreatureStaticFlags4 flag) const { return _staticFlags.HasFlag(flag); }
bool HasStaticFlag(CreatureStaticFlags5 flag) const { return _staticFlags.HasFlag(flag); }
uint32 GetGossipMenuId() const;
void SetGossipMenuId(uint32 gossipMenuId);
CreatureMovementInfo const& GetCreatureMovementInfo() const { return _creatureMovementInfo; }
// Sets the the max health percentage threshold at which uncontrolled/unowned creatures can no longer deal damage to the creature
@@ -508,6 +511,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
Optional<uint32> _defaultMountDisplayIdOverride;
float _noNpcDamageBelowPctHealth;
uint32 _gossipMenuId;
};
class TC_GAME_API AssistDelayEvent : public BasicEvent
@@ -365,7 +365,7 @@ struct TC_GAME_API CreatureTemplate
std::string FemaleName;
std::string Title;
std::string IconName;
uint32 GossipMenuId;
std::vector<uint32> GossipMenuIds;
uint8 minlevel;
uint8 maxlevel;
int32 HealthScalingExpansion;
+29 -4
View File
@@ -13385,7 +13385,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
GossipMenuItemsMapBounds menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(menuId);
// if default menuId and no menu options exist for this, use options from default options
if (menuItemBounds.first == menuItemBounds.second && menuId == GetDefaultGossipMenuForSource(source))
if (menuItemBounds.first == menuItemBounds.second && menuId == GetGossipMenuForSource(source))
menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(0);
uint32 npcflags = 0;
@@ -13701,7 +13701,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)
@@ -13715,6 +13715,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;
}
@@ -13722,12 +13726,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()->GetCreatureTemplate()->GossipMenuId;
{
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:
+1 -1
View File
@@ -1296,7 +1296,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 ***/
+121 -77
View File
@@ -413,21 +413,21 @@ void ObjectMgr::LoadCreatureTemplates()
{
uint32 oldMSTime = getMSTime();
// 0 1 2 3 4 5 6 7 8
// 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 21 22
"modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, exp_unk, faction, npcflag, speed_walk, speed_run, "
// 23 24 25 26 27 28 29 30 31 32
// 9 10 11 12 13 14 15 16 17 18 19 20 21
"modelid4, name, femaleName, subname, IconName, minlevel, maxlevel, HealthScalingExpansion, exp_unk, faction, npcflag, speed_walk, speed_run, "
// 22 23 24 25 26 27 28 29 30 31
"scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, "
// 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// 32 33 34 35 36 37 38 39 40 41 42 43 44 45
"family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, "
// 47 48 49 50 51 52 53 54 55 56 57 58 59 60
// 46 47 48 49 50 51 52 53 54 55 56 57 58 59
"spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
// 61 62 63 64 65 66 67 68 69
// 60 61 62 63 64 65 66 67 68
"ctm.HoverInitiallyEnabled, ctm.GravityInitiallyDisabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, "
// 70 71 72 73 74 75 76 77
// 69 70 71 72 73 74 75 76
"ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, "
// 78 79 80 81 82 83 84
// 77 78 79 80 81 82 83
"flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId");
if (!result)
@@ -468,84 +468,77 @@ 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.Title = fields[12].GetString();
creatureTemplate.IconName = fields[13].GetString();
creatureTemplate.GossipMenuId = fields[14].GetUInt32();
creatureTemplate.minlevel = fields[15].GetUInt8();
creatureTemplate.maxlevel = fields[16].GetUInt8();
creatureTemplate.HealthScalingExpansion = fields[17].GetInt32();
creatureTemplate.expansionUnknown = uint32(fields[18].GetUInt16());
creatureTemplate.faction = uint32(fields[19].GetUInt16());
creatureTemplate.npcflag = fields[20].GetUInt32();
creatureTemplate.speed_walk = fields[21].GetFloat();
creatureTemplate.speed_run = fields[22].GetFloat();
creatureTemplate.scale = fields[23].GetFloat();
creatureTemplate.rank = uint32(fields[24].GetUInt8());
creatureTemplate.dmgschool = uint32(fields[25].GetInt8());
creatureTemplate.BaseAttackTime = fields[26].GetUInt32();
creatureTemplate.RangeAttackTime = fields[27].GetUInt32();
creatureTemplate.BaseVariance = fields[28].GetFloat();
creatureTemplate.RangeVariance = fields[29].GetFloat();
creatureTemplate.unit_class = uint32(fields[30].GetUInt8());
creatureTemplate.unit_flags = fields[31].GetUInt32();
creatureTemplate.unit_flags2 = fields[32].GetUInt32();
creatureTemplate.family = CreatureFamily(uint32(fields[33].GetUInt8()));
creatureTemplate.trainer_class = fields[34].GetUInt32();
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();
creatureTemplate.Name = fields[10].GetString();
creatureTemplate.FemaleName = fields[11].GetString();
creatureTemplate.Title = fields[12].GetString();
creatureTemplate.IconName = fields[13].GetString();
creatureTemplate.minlevel = fields[14].GetUInt8();
creatureTemplate.maxlevel = fields[15].GetUInt8();
creatureTemplate.HealthScalingExpansion = fields[16].GetInt32();
creatureTemplate.expansionUnknown = uint32(fields[17].GetInt16());
creatureTemplate.faction = uint32(fields[18].GetUInt16());
creatureTemplate.npcflag = fields[19].GetUInt32();
creatureTemplate.speed_walk = fields[20].GetFloat();
creatureTemplate.speed_run = fields[21].GetFloat();
creatureTemplate.scale = fields[22].GetFloat();
creatureTemplate.rank = uint32(fields[23].GetUInt8());
creatureTemplate.dmgschool = uint32(fields[24].GetInt8());
creatureTemplate.BaseAttackTime = fields[25].GetUInt32();
creatureTemplate.RangeAttackTime = fields[26].GetUInt32();
creatureTemplate.BaseVariance = fields[27].GetFloat();
creatureTemplate.RangeVariance = fields[28].GetFloat();
creatureTemplate.unit_class = uint32(fields[29].GetUInt8());
creatureTemplate.unit_flags = fields[30].GetUInt32();
creatureTemplate.unit_flags2 = fields[31].GetUInt32();
creatureTemplate.family = CreatureFamily(uint32(fields[32].GetUInt8()));
creatureTemplate.trainer_class = fields[33].GetUInt32();
creatureTemplate.type = uint32(fields[34].GetUInt8());
creatureTemplate.type_flags = fields[35].GetUInt32();
creatureTemplate.type_flags2 = fields[36].GetUInt32();
creatureTemplate.lootid = fields[37].GetUInt32();
creatureTemplate.pickpocketLootId = fields[38].GetUInt32();
creatureTemplate.SkinLootId = fields[39].GetUInt32();
for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
creatureTemplate.resistance[i] = fields[41 + i - 1].GetInt16();
creatureTemplate.resistance[i] = fields[40 + i - 1].GetInt16();
for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
creatureTemplate.spells[i] = fields[47 + i].GetUInt32();
creatureTemplate.spells[i] = fields[46 + i].GetUInt32();
creatureTemplate.PetSpellDataId = fields[54].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());
if (!fields[60].IsNull())
creatureTemplate.Movement.HoverInitiallyEnabled = fields[60].GetBool();
creatureTemplate.PetSpellDataId = fields[55].GetUInt32();
creatureTemplate.VehicleId = fields[56].GetUInt32();
creatureTemplate.mingold = fields[57].GetUInt32();
creatureTemplate.maxgold = fields[58].GetUInt32();
creatureTemplate.AIName = fields[59].GetString();
creatureTemplate.MovementType = uint32(fields[60].GetUInt8());
if (!fields[61].IsNull())
creatureTemplate.Movement.HoverInitiallyEnabled = fields[61].GetBool();
creatureTemplate.Movement.GravityInitiallyDisabled = fields[61].GetBool();
if (!fields[62].IsNull())
creatureTemplate.Movement.GravityInitiallyDisabled = fields[62].GetBool();
creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[62].GetUInt8());
if (!fields[63].IsNull())
creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[63].GetUInt8());
creatureTemplate.Movement.InteractionPauseTimer = fields[63].GetUInt32();
creatureTemplate.HoverHeight = fields[64].GetFloat();
creatureTemplate.ModHealth = fields[65].GetFloat();
creatureTemplate.ModHealthExtra = fields[66].GetFloat();
creatureTemplate.ModMana = fields[67].GetFloat();
creatureTemplate.ModManaExtra = fields[68].GetFloat();
creatureTemplate.ModArmor = fields[69].GetFloat();
creatureTemplate.ModDamage = fields[70].GetFloat();
creatureTemplate.ModExperience = fields[71].GetFloat();
if (!fields[64].IsNull())
creatureTemplate.Movement.InteractionPauseTimer = fields[64].GetUInt32();
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.SpellSchoolImmuneMask = fields[77].GetUInt32();
creatureTemplate.flags_extra = fields[78].GetUInt32();
creatureTemplate.StaticFlags = CreatureStaticFlagsHolder(CreatureStaticFlags(fields[79].GetUInt32()), CreatureStaticFlags2(fields[80].GetUInt32()),
CreatureStaticFlags3(fields[81].GetUInt32()), CreatureStaticFlags4(fields[82].GetUInt32()), CreatureStaticFlags5(fields[83].GetUInt32()));
creatureTemplate.ScriptID = GetScriptId(fields[84].GetCString());
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.StaticFlags = CreatureStaticFlagsHolder(CreatureStaticFlags(fields[78].GetUInt32()), CreatureStaticFlags2(fields[79].GetUInt32()),
CreatureStaticFlags3(fields[80].GetUInt32()), CreatureStaticFlags4(fields[81].GetUInt32()), CreatureStaticFlags5(fields[82].GetUInt32()));
creatureTemplate.ScriptID = GetScriptId(fields[83].GetCString());
}
void ObjectMgr::LoadCreatureTemplateModels()
@@ -603,6 +596,52 @@ void ObjectMgr::LoadCreatureTemplateModels()
TC_LOG_INFO("server.loading", ">> Loaded %u creature template models in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
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::LoadCreatureTemplateAddons()
{
uint32 oldMSTime = getMSTime();
@@ -1129,6 +1168,11 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
}
const_cast<CreatureTemplate*>(cInfo)->ModDamage *= Creature::_GetDamageMod(cInfo->rank);
if (!cInfo->GossipMenuIds.empty() && !(cInfo->npcflag & UNIT_NPC_FLAG_GOSSIP))
TC_LOG_INFO("sql.sql", "Creature (Entry: %u) 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: %u) has npcflag UNIT_NPC_FLAG_GOSSIP, but gossip menu is unassigned.", cInfo->Entry);
}
void ObjectMgr::CheckCreatureMovement(char const* table, uint64 id, CreatureMovementData& creatureMovement)
+1
View File
@@ -1176,6 +1176,7 @@ class TC_GAME_API ObjectMgr
void LoadCreatureSparringTemplate();
void LoadCreatureTemplate(Field* fields);
void LoadCreatureTemplateModels();
void LoadCreatureTemplateGossip();
void CheckCreatureTemplate(CreatureTemplate const* cInfo);
void CheckCreatureMovement(char const* table, uint64 id, CreatureMovementData& creatureMovement);
void LoadGameObjectQuestItems();
+1 -1
View File
@@ -201,7 +201,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet)
if (!unit->AI()->GossipHello(_player))
{
// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID());
_player->PrepareGossipMenu(unit, unit->GetCreatureTemplate()->GossipMenuId, true);
_player->PrepareGossipMenu(unit, _player->GetGossipMenuForSource(unit), true);
// If npc is a flightmaster who is a quest giver do not send the gossip if there is no quest
if (unit->IsTaxi() && (unit->IsQuestGiver() || unit->IsGossip()))
+2 -2
View File
@@ -98,7 +98,7 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPackets::Quest::QuestGiverHe
if (creature->AI()->GossipHello(_player))
return;
_player->PrepareGossipMenu(creature, creature->GetCreatureTemplate()->GossipMenuId, true);
_player->PrepareGossipMenu(creature, _player->GetGossipMenuForSource(creature), true);
_player->SendPreparedGossip(creature);
}
@@ -227,7 +227,7 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPackets::Quest::QuestG
auto launchGossip = [&](WorldObject* worldObject)
{
_player->PlayerTalkClass->ClearMenus();
_player->PrepareGossipMenu(worldObject, _player->GetDefaultGossipMenuForSource(worldObject), true);
_player->PrepareGossipMenu(worldObject, _player->GetGossipMenuForSource(worldObject), true);
_player->SendPreparedGossip(worldObject);
};
+3
View File
@@ -2143,6 +2143,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Gossip menu options...");
sObjectMgr->LoadGossipMenuItems();
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
@@ -650,7 +650,7 @@ public:
if (player->IsInCombat() || me->IsInCombat())
return true;
AddGossipItemFor(player, Player::GetDefaultGossipMenuForSource(me), 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;
@@ -366,7 +366,9 @@ enum MiscData
enum Misc
{
DATA_PLAGUE_STACK = 70337,
DATA_VILE = 45814622
DATA_VILE = 45814622,
GOSSIP_MENU_START_INTRO = 10993
};
class NecroticPlagueTargetCheck
@@ -1206,7 +1208,7 @@ class npc_tirion_fordring_tft : public CreatureScript
bool GossipSelect(Player* /*player*/, uint32 menuId, uint32 gossipListId) override
{
if (me->GetCreatureTemplate()->GossipMenuId == menuId && !gossipListId)
if (menuId == GOSSIP_MENU_START_INTRO && !gossipListId)
{
_events.SetPhase(PHASE_INTRO);
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);