Core/Creatures: Move gossip trainer assignment to creature_trainer table - same gossip can open different trainers depending on which creature it is assigned to

Closes #21723
This commit is contained in:
Shauren
2020-07-31 11:21:24 +02:00
parent 8116ad5889
commit 1340f2cdb3
8 changed files with 478 additions and 35 deletions

View File

@@ -133,17 +133,16 @@ void GossipMenu::AddMenuItem(uint32 menuId, uint32 optionIndex, uint32 sender, u
/// Add menu item with existing method. Menu item id -1 is also used in ADD_GOSSIP_ITEM macro.
uint32 newOptionIndex = AddMenuItem(-1, itr->second.OptionIcon, strOptionText, sender, action, strBoxText, itr->second.BoxMoney, itr->second.BoxCoded);
AddGossipMenuItemData(newOptionIndex, itr->second.ActionMenuId, itr->second.ActionPoiId, itr->second.TrainerId);
AddGossipMenuItemData(newOptionIndex, itr->second.ActionMenuId, itr->second.ActionPoiId);
}
}
void GossipMenu::AddGossipMenuItemData(uint32 optionIndex, uint32 gossipActionMenuId, uint32 gossipActionPoi, uint32 trainerId)
void GossipMenu::AddGossipMenuItemData(uint32 optionIndex, uint32 gossipActionMenuId, uint32 gossipActionPoi)
{
GossipMenuItemData& itemData = _menuItemData[optionIndex];
itemData.GossipActionMenuId = gossipActionMenuId;
itemData.GossipActionPoi = gossipActionPoi;
itemData.TrainerId = trainerId;
}
uint32 GossipMenu::GetMenuItemSender(uint32 menuItemId) const

View File

@@ -147,8 +147,6 @@ struct GossipMenuItemData
{
uint32 GossipActionMenuId; // MenuId of the gossip triggered by this action
uint32 GossipActionPoi;
uint32 TrainerId;
};
// need an ordered container
@@ -176,7 +174,7 @@ class TC_GAME_API GossipMenu
void SetLocale(LocaleConstant locale) { _locale = locale; }
LocaleConstant GetLocale() const { return _locale; }
void AddGossipMenuItemData(uint32 optionIndex, uint32 gossipActionMenuId, uint32 gossipActionPoi, uint32 trainerId);
void AddGossipMenuItemData(uint32 optionIndex, uint32 gossipActionMenuId, uint32 gossipActionPoi);
uint32 GetMenuItemCount() const { return uint32(_menuItems.size()); }
bool Empty() const { return _menuItems.empty(); }

View File

@@ -14712,7 +14712,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
}
menu->GetGossipMenu().AddMenuItem(itr->second.OptionIndex, itr->second.OptionIcon, strOptionText, 0, itr->second.OptionType, strBoxText, itr->second.BoxMoney, itr->second.BoxCoded);
menu->GetGossipMenu().AddGossipMenuItemData(itr->second.OptionIndex, itr->second.ActionMenuId, itr->second.ActionPoiId, itr->second.TrainerId);
menu->GetGossipMenu().AddGossipMenuItemData(itr->second.OptionIndex, itr->second.ActionMenuId, itr->second.ActionPoiId);
}
}
}
@@ -14813,7 +14813,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 optionIndex, uint32 menu
GetSession()->SendStablePet(guid);
break;
case GOSSIP_OPTION_TRAINER:
GetSession()->SendTrainerList(source->ToCreature(), menuItemData->TrainerId);
GetSession()->SendTrainerList(source->ToCreature(), sObjectMgr->GetCreatureTrainerForGossipOption(source->GetEntry(), menuId, optionIndex));
break;
case GOSSIP_OPTION_LEARNDUALSPEC:
break;

View File

@@ -8738,33 +8738,51 @@ void ObjectMgr::LoadTrainers()
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Trainers in %u ms", _trainers.size(), GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadCreatureDefaultTrainers()
void ObjectMgr::LoadCreatureTrainers()
{
uint32 oldMSTime = getMSTime();
_creatureDefaultTrainers.clear();
if (QueryResult result = WorldDatabase.Query("SELECT CreatureId, TrainerId FROM creature_default_trainer"))
if (QueryResult result = WorldDatabase.Query("SELECT CreatureId, TrainerId, MenuId, OptionIndex FROM creature_trainer"))
{
do
{
Field* fields = result->Fetch();
uint32 creatureId = fields[0].GetUInt32();
uint32 trainerId = fields[1].GetUInt32();
uint32 gossipMenuId = fields[2].GetUInt32();
uint32 gossipOptionIndex = fields[3].GetUInt32();
if (!GetCreatureTemplate(creatureId))
{
TC_LOG_ERROR("sql.sql", "Table `creature_default_trainer` references non-existing creature template (CreatureId: %u), ignoring", creatureId);
TC_LOG_ERROR("sql.sql", "Table `creature_trainer` references non-existing creature template (CreatureId: %u), ignoring", creatureId);
continue;
}
if (!GetTrainer(trainerId))
{
TC_LOG_ERROR("sql.sql", "Table `creature_default_trainer` references non-existing trainer (TrainerId: %u) for CreatureId %u, ignoring", trainerId, creatureId);
TC_LOG_ERROR("sql.sql", "Table `creature_trainer` references non-existing trainer (TrainerId: %u) for CreatureId %u MenuId %u OptionIndex %u, ignoring",
trainerId, creatureId, gossipMenuId, gossipOptionIndex);
continue;
}
_creatureDefaultTrainers[creatureId] = trainerId;
if (gossipMenuId || gossipOptionIndex)
{
Trinity::IteratorPair<GossipMenuItemsContainer::const_iterator> gossipMenuItems = GetGossipMenuItemsMapBounds(gossipMenuId);
auto gossipOptionItr = std::find_if(gossipMenuItems.begin(), gossipMenuItems.end(), [gossipOptionIndex](std::pair<uint32 const, GossipMenuItems> const& entry)
{
return entry.second.OptionIndex == gossipOptionIndex;
});
if (gossipOptionItr == gossipMenuItems.end())
{
TC_LOG_ERROR("sql.sql", "Table `creature_trainer` references non-existing gossip menu option (MenuId %u OptionIndex %u) for CreatureId %u and TrainerId %u, ignoring",
gossipMenuId, gossipOptionIndex, creatureId, trainerId);
continue;
}
}
_creatureDefaultTrainers[std::make_tuple(creatureId, gossipMenuId, gossipOptionIndex)] = trainerId;
} while (result->NextRow());
}
@@ -8924,13 +8942,10 @@ void ObjectMgr::LoadGossipMenuItems()
// 7 8
"oa.ActionMenuId, oa.ActionPoiId, "
// 9 10 11 12
"ob.BoxCoded, ob.BoxMoney, ob.BoxText, ob.BoxBroadcastTextId, "
// 13
"ot.TrainerId "
"ob.BoxCoded, ob.BoxMoney, ob.BoxText, ob.BoxBroadcastTextId "
"FROM gossip_menu_option o "
"LEFT JOIN gossip_menu_option_action oa ON o.MenuId = oa.MenuId AND o.OptionIndex = oa.OptionIndex "
"LEFT JOIN gossip_menu_option_box ob ON o.MenuId = ob.MenuId AND o.OptionIndex = ob.OptionIndex "
"LEFT JOIN gossip_menu_option_trainer ot ON o.MenuId = ot.MenuId AND o.OptionIndex = ot.OptionIndex "
"ORDER BY o.MenuId, o.OptionIndex");
if (!result)
@@ -8958,7 +8973,6 @@ void ObjectMgr::LoadGossipMenuItems()
gMenuItem.BoxMoney = fields[10].GetUInt32();
gMenuItem.BoxText = fields[11].GetString();
gMenuItem.BoxBroadcastTextId = fields[12].GetUInt32();
gMenuItem.TrainerId = fields[13].GetUInt32();
if (gMenuItem.OptionIcon >= GOSSIP_ICON_MAX)
{
@@ -8993,12 +9007,6 @@ void ObjectMgr::LoadGossipMenuItems()
}
}
if (gMenuItem.TrainerId && !GetTrainer(gMenuItem.TrainerId))
{
TC_LOG_ERROR("sql.sql", "Table `gossip_menu_option_trainer` for MenuId %u, OptionIndex %u use non-existing TrainerId %u, ignoring", gMenuItem.MenuId, gMenuItem.OptionIndex, gMenuItem.TrainerId);
gMenuItem.TrainerId = 0;
}
_gossipMenuItemsStore.insert(GossipMenuItemsContainer::value_type(gMenuItem.MenuId, gMenuItem));
} while (result->NextRow());
@@ -9010,9 +9018,9 @@ Trainer::Trainer const* ObjectMgr::GetTrainer(uint32 trainerId) const
return Trinity::Containers::MapGetValuePtr(_trainers, trainerId);
}
uint32 ObjectMgr::GetCreatureDefaultTrainer(uint32 creatureId) const
uint32 ObjectMgr::GetCreatureTrainerForGossipOption(uint32 creatureId, uint32 gossipMenuId, uint32 gossipOptionIndex) const
{
auto itr = _creatureDefaultTrainers.find(creatureId);
auto itr = _creatureDefaultTrainers.find(std::make_tuple(creatureId, gossipMenuId, gossipOptionIndex));
if (itr != _creatureDefaultTrainers.end())
return itr->second;

View File

@@ -682,7 +682,6 @@ struct GossipMenuItems
uint32 BoxMoney;
std::string BoxText;
uint32 BoxBroadcastTextId;
uint32 TrainerId;
ConditionContainer Conditions;
};
@@ -1297,7 +1296,7 @@ class TC_GAME_API ObjectMgr
void LoadVendors();
void LoadTrainers();
void LoadCreatureDefaultTrainers();
void LoadCreatureTrainers();
void LoadPhases();
void UnloadPhaseConditions();
@@ -1519,7 +1518,11 @@ class TC_GAME_API ObjectMgr
bool DeleteGameTele(std::string const& name);
Trainer::Trainer const* GetTrainer(uint32 trainerId) const;
uint32 GetCreatureDefaultTrainer(uint32 creatureId) const;
uint32 GetCreatureDefaultTrainer(uint32 creatureId) const
{
return GetCreatureTrainerForGossipOption(creatureId, 0, 0);
}
uint32 GetCreatureTrainerForGossipOption(uint32 creatureId, uint32 gossipMenuId, uint32 gossipOptionIndex) const;
VendorItemData const* GetNpcVendorItemList(uint32 entry) const
{
@@ -1779,7 +1782,7 @@ class TC_GAME_API ObjectMgr
CacheVendorItemContainer _cacheVendorItemStore;
std::unordered_map<uint32, Trainer::Trainer> _trainers;
std::unordered_map<uint32, uint32> _creatureDefaultTrainers;
std::map<std::tuple<uint32, uint32, uint32>, uint32> _creatureDefaultTrainers;
std::set<uint32> _difficultyEntries[MAX_CREATURE_DIFFICULTIES]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate
std::set<uint32> _hasDifficultyEntries[MAX_CREATURE_DIFFICULTIES]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate

View File

@@ -1995,14 +1995,14 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Trainers...");
sObjectMgr->LoadTrainers(); // must be after load CreatureTemplate
TC_LOG_INFO("server.loading", "Loading Creature default trainers...");
sObjectMgr->LoadCreatureDefaultTrainers();
TC_LOG_INFO("server.loading", "Loading Gossip menu...");
sObjectMgr->LoadGossipMenu();
TC_LOG_INFO("server.loading", "Loading Gossip menu options...");
sObjectMgr->LoadGossipMenuItems(); // must be after LoadTrainers
sObjectMgr->LoadGossipMenuItems();
TC_LOG_INFO("server.loading", "Loading Creature trainers...");
sObjectMgr->LoadCreatureTrainers(); // must be after LoadGossipMenuItems
TC_LOG_INFO("server.loading", "Loading Vendors...");
sObjectMgr->LoadVendors(); // must be after load CreatureTemplate and ItemTemplate

View File

@@ -696,7 +696,7 @@ public:
{
TC_LOG_INFO("misc", "Re-Loading `trainer` Table!");
sObjectMgr->LoadTrainers();
sObjectMgr->LoadCreatureDefaultTrainers();
sObjectMgr->LoadCreatureTrainers();
handler->SendGlobalGMSysMessage("DB table `trainer` reloaded.");
handler->SendGlobalGMSysMessage("DB table `trainer_locale` reloaded.");
handler->SendGlobalGMSysMessage("DB table `trainer_spell` reloaded.");