diff --git a/sql/updates/world/master/2024_12_29_00_world.sql b/sql/updates/world/master/2024_12_29_00_world.sql new file mode 100644 index 0000000000000..2209d1f7306ec --- /dev/null +++ b/sql/updates/world/master/2024_12_29_00_world.sql @@ -0,0 +1,19 @@ +UPDATE `trinity_string` SET `content_default`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291; +UPDATE `trinity_string` SET `content_loc1`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291 AND `content_loc1` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc2`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291 AND `content_loc2` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc3`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291 AND `content_loc3` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc4`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291 AND `content_loc4` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc5`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291 AND `content_loc5` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc6`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291 AND `content_loc6` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc7`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291 AND `content_loc7` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc8`='├%.*s %dx |c%08x|Hitem:%d:0:0:0:0:0:0:0:0|h[%s]|h|r (#%05d)' WHERE `entry`=291 AND `content_loc8` IS NOT NULL; + +UPDATE `trinity_string` SET `content_default`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295; +UPDATE `trinity_string` SET `content_loc1`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295 AND `content_loc1` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc2`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295 AND `content_loc2` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc3`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295 AND `content_loc3` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc4`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295 AND `content_loc4` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc5`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295 AND `content_loc5` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc6`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295 AND `content_loc6` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc7`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295 AND `content_loc7` IS NOT NULL; +UPDATE `trinity_string` SET `content_loc8`='├%.*s |cffffff00|Hquest:%u:0|h[%.*s]|h|r (#%05d)' WHERE `entry`=295 AND `content_loc8` IS NOT NULL; diff --git a/src/server/game/AI/CoreAI/AreaTriggerAI.h b/src/server/game/AI/CoreAI/AreaTriggerAI.h index 55e8f188586dc..c163929114349 100644 --- a/src/server/game/AI/CoreAI/AreaTriggerAI.h +++ b/src/server/game/AI/CoreAI/AreaTriggerAI.h @@ -61,10 +61,10 @@ class TC_GAME_API AreaTriggerAI // Pass parameters between AI virtual void DoAction([[maybe_unused]] int32 param) { } - virtual uint32 GetData([[maybe_unused]] uint32 id = 0) const { return 0; } + virtual uint32 GetData([[maybe_unused]] uint32 id) const { return 0; } virtual void SetData([[maybe_unused]] uint32 id, [[maybe_unused]] uint32 value) { } - virtual void SetGUID([[maybe_unused]] ObjectGuid const& guid, [[maybe_unused]] int32 id = 0) { } - virtual ObjectGuid GetGUID([[maybe_unused]] int32 id = 0) const { return ObjectGuid::Empty; } + virtual void SetGUID([[maybe_unused]] ObjectGuid const& guid, [[maybe_unused]] int32 id) { } + virtual ObjectGuid GetGUID([[maybe_unused]] int32 id) const { return ObjectGuid::Empty; } // Gets the id of the AI (script id) uint32 GetId() const { return _scriptId; } diff --git a/src/server/game/AI/CoreAI/ConversationAI.cpp b/src/server/game/AI/CoreAI/ConversationAI.cpp new file mode 100644 index 0000000000000..19de90c6ad24e --- /dev/null +++ b/src/server/game/AI/CoreAI/ConversationAI.cpp @@ -0,0 +1,28 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Conversation.h" +#include "ConversationAI.h" + +ConversationAI::ConversationAI(Conversation* c, uint32 scriptId) : _scriptId(scriptId ? scriptId : c->GetScriptId()), conversation(c) +{ + ASSERT(_scriptId, "A ConversationAI was initialized with an invalid scriptId!"); +} + +ConversationAI::~ConversationAI() +{ +} diff --git a/src/server/game/AI/CoreAI/ConversationAI.h b/src/server/game/AI/CoreAI/ConversationAI.h new file mode 100644 index 0000000000000..3a41d0f1b60fe --- /dev/null +++ b/src/server/game/AI/CoreAI/ConversationAI.h @@ -0,0 +1,73 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef TRINITY_CONVERSATIONAI_H +#define TRINITY_CONVERSATIONAI_H + +#include "Define.h" +#include "ObjectGuid.h" + +class Conversation; +class Unit; +class Player; + +class TC_GAME_API ConversationAI +{ + uint32 _scriptId; + + protected: + Conversation* const conversation; + public: + explicit ConversationAI(Conversation* c, uint32 scriptId = {}); + virtual ~ConversationAI(); + + // Called when the Conversation has just been initialized, just before added to map + virtual void OnInitialize() {} + + // Called when Conversation is created but not added to Map yet. + virtual void OnCreate([[maybe_unused]] Unit* creator) { } + + // Called when Conversation is started + virtual void OnStart() { } + + // Called when player sends CMSG_CONVERSATION_LINE_STARTED with valid conversation guid + virtual void OnLineStarted([[maybe_unused]] uint32 lineId, [[maybe_unused]] Player* sender) { } + + // Called for each update tick + virtual void OnUpdate([[maybe_unused]] uint32 diff) { } + + // Called when the Conversation is removed + virtual void OnRemove() { } + + // Pass parameters between AI + virtual void DoAction([[maybe_unused]] int32 param) { } + virtual uint32 GetData([[maybe_unused]] uint32 id) const { return 0; } + virtual void SetData([[maybe_unused]] uint32 id, [[maybe_unused]] uint32 value) { } + virtual void SetGUID([[maybe_unused]] ObjectGuid const& guid, [[maybe_unused]] int32 id) { } + virtual ObjectGuid GetGUID([[maybe_unused]] int32 id) const { return ObjectGuid::Empty; } + + // Gets the id of the AI (script id) + uint32 GetId() const { return _scriptId; } +}; + +class NullConversationAI final : public ConversationAI +{ + public: + using ConversationAI::ConversationAI; +}; + +#endif diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index b99a9e8180cf3..40e5688724408 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -63,9 +63,9 @@ class TC_GAME_API GameObjectAI virtual void Reset() { } // Pass parameters between AI - virtual void DoAction(int32 /*param = 0 */) { } - virtual void SetGUID(ObjectGuid const& /*guid*/, int32 /*id = 0 */) { } - virtual ObjectGuid GetGUID(int32 /*id = 0 */) const { return ObjectGuid::Empty; } + virtual void DoAction([[maybe_unused]] int32 param) { } + virtual void SetGUID([[maybe_unused]] ObjectGuid const& guid, [[maybe_unused]] int32 id) { } + virtual ObjectGuid GetGUID([[maybe_unused]] int32 id) const { return ObjectGuid::Empty; } static int32 Permissible(GameObject const* go); diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 847888c5d5082..669414c1fff68 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -69,11 +69,11 @@ class TC_GAME_API UnitAI virtual void OnCharmed(bool isNew); // Pass parameters between AI - virtual void DoAction(int32 /*param*/) { } - virtual uint32 GetData(uint32 /*id = 0*/) const { return 0; } - virtual void SetData(uint32 /*id*/, uint32 /*value*/) { } - virtual void SetGUID(ObjectGuid const& /*guid*/, int32 /*id*/ = 0) { } - virtual ObjectGuid GetGUID(int32 /*id*/ = 0) const { return ObjectGuid::Empty; } + virtual void DoAction([[maybe_unused]] int32 param) { } + virtual uint32 GetData([[maybe_unused]] uint32 id) const { return 0; } + virtual void SetData([[maybe_unused]] uint32 id, [[maybe_unused]] uint32 value) { } + virtual void SetGUID([[maybe_unused]] ObjectGuid const& guid, [[maybe_unused]] int32 id) { } + virtual ObjectGuid GetGUID([[maybe_unused]] int32 id) const { return ObjectGuid::Empty; } // Select the best target (in order) from the threat list that fulfill the following: // - Not among the first entries in order (or SelectTargetMethod::MaxThreat order, diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index c6a8871a822a3..ec22e9e4ebae1 100644 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -28,6 +28,9 @@ #include "AreaTriggerAI.h" +#include "Conversation.h" +#include "ConversationAI.h" + #include "ScriptMgr.h" namespace FactorySelector @@ -187,4 +190,28 @@ namespace FactorySelector return GetNullAreaTriggerAIScriptId(); } + + static uint32 GetNullConversationAIScriptId() + { + return sObjectMgr->GetScriptId("NullConversationAI", false); + } + + ConversationAI* SelectConversationAI(Conversation* conversation) + { + if (ConversationAI* ai = sScriptMgr->GetConversationAI(conversation)) + return ai; + + return new NullConversationAI(conversation, GetNullConversationAIScriptId()); + } + + uint32 GetSelectedAIId(Conversation const* conversation) + { + if (uint32 id = conversation->GetScriptId()) + { + if (sScriptMgr->CanCreateConversationAI(id)) + return id; + } + + return GetNullConversationAIScriptId(); + } } diff --git a/src/server/game/AI/CreatureAISelector.h b/src/server/game/AI/CreatureAISelector.h index 0cb6c9632b308..d2ee805706fe6 100644 --- a/src/server/game/AI/CreatureAISelector.h +++ b/src/server/game/AI/CreatureAISelector.h @@ -28,6 +28,8 @@ class GameObjectAI; class GameObject; class AreaTriggerAI; class AreaTrigger; +class Conversation; +class ConversationAI; namespace FactorySelector { @@ -35,10 +37,12 @@ namespace FactorySelector TC_GAME_API MovementGenerator* SelectMovementGenerator(Unit* unit); TC_GAME_API GameObjectAI* SelectGameObjectAI(GameObject* go); TC_GAME_API AreaTriggerAI* SelectAreaTriggerAI(AreaTrigger* at); + TC_GAME_API ConversationAI* SelectConversationAI(Conversation* conversation); TC_GAME_API uint32 GetSelectedAIId(Creature const* creature); TC_GAME_API uint32 GetSelectedAIId(GameObject const* go); TC_GAME_API uint32 GetSelectedAIId(AreaTrigger const* at); + TC_GAME_API uint32 GetSelectedAIId(Conversation const* conversation); } #endif diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 16a7790a64586..02e9b73bb768a 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -174,20 +174,20 @@ class TC_GAME_API SmartAI : public CreatureAI void OnCharmed(bool isNew) override; // Used in scripts to share variables - void DoAction(int32 param = 0) override; + void DoAction(int32 param) override; // Used in scripts to share variables - uint32 GetData(uint32 id = 0) const override; + uint32 GetData(uint32 id) const override; // Used in scripts to share variables void SetData(uint32 id, uint32 value) override { SetData(id, value, nullptr); } void SetData(uint32 id, uint32 value, Unit* invoker); // Used in scripts to share variables - void SetGUID(ObjectGuid const& guid, int32 id = 0) override; + void SetGUID(ObjectGuid const& guid, int32 id) override; // Used in scripts to share variables - ObjectGuid GetGUID(int32 id = 0) const override; + ObjectGuid GetGUID(int32 id) const override; // Makes the creature run/walk void SetRun(bool run = true); diff --git a/src/server/game/Entities/Conversation/Conversation.cpp b/src/server/game/Entities/Conversation/Conversation.cpp index fa1d52041650c..746f936a88c93 100644 --- a/src/server/game/Entities/Conversation/Conversation.cpp +++ b/src/server/game/Entities/Conversation/Conversation.cpp @@ -18,8 +18,10 @@ #include "Conversation.h" #include "ConditionMgr.h" #include "Containers.h" +#include "ConversationAI.h" #include "ConversationDataStore.h" #include "Creature.h" +#include "CreatureAISelector.h" #include "DB2Stores.h" #include "IteratorPair.h" #include "Log.h" @@ -61,6 +63,8 @@ void Conversation::RemoveFromWorld() ///- Remove the Conversation from the accessor and from all lists of objects in world if (IsInWorld()) { + _ai->OnRemove(); + WorldObject::RemoveFromWorld(); GetMap()->GetObjectsStore().Remove(GetGUID()); } @@ -68,7 +72,7 @@ void Conversation::RemoveFromWorld() void Conversation::Update(uint32 diff) { - sScriptMgr->OnConversationUpdate(this, diff); + _ai->OnUpdate(diff); if (GetDuration() > Milliseconds(diff)) { @@ -183,6 +187,8 @@ void Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry, SetEntry(conversationEntry); SetObjectScale(1.0f); + AI_Initialize(); + _textureKitId = conversationTemplate->TextureKitId; for (ConversationActorTemplate const& actor : conversationTemplate->Actors) @@ -227,7 +233,7 @@ void Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry, // conversations are despawned 5-20s after LastLineEndTime _duration += 10s; - sScriptMgr->OnConversationCreate(this, creator); + _ai->OnCreate(creator); } bool Conversation::Start() @@ -255,7 +261,7 @@ bool Conversation::Start() if (!GetMap()->AddToMap(this)) return false; - sScriptMgr->OnConversationStart(this); + _ai->OnStart(); return true; } @@ -344,6 +350,18 @@ Creature* Conversation::GetActorCreature(uint32 actorIdx) const return actor->ToCreature(); } +void Conversation::AI_Initialize() +{ + AI_Destroy(); + _ai.reset(FactorySelector::SelectConversationAI(this)); + _ai->OnInitialize(); +} + +void Conversation::AI_Destroy() +{ + _ai.reset(); +} + uint32 Conversation::GetScriptId() const { return sConversationDataStore->GetConversationTemplate(GetEntry())->ScriptId; diff --git a/src/server/game/Entities/Conversation/Conversation.h b/src/server/game/Entities/Conversation/Conversation.h index f56c8e1d3c666..4f85809b5ba87 100644 --- a/src/server/game/Entities/Conversation/Conversation.h +++ b/src/server/game/Entities/Conversation/Conversation.h @@ -22,6 +22,7 @@ #include "GridObject.h" #include "Hash.h" +class ConversationAI; class Unit; class SpellInfo; enum class ConversationActorType : uint32; @@ -85,6 +86,10 @@ class TC_GAME_API Conversation final : public WorldObject, public GridObject m_conversationData; @@ -97,6 +102,8 @@ class TC_GAME_API Conversation final : public WorldObject, public GridObject, Milliseconds /*startTime*/> _lineStartTimes; std::array _lastLineEndTimes; + + std::unique_ptr _ai; }; #endif // TRINITYCORE_CONVERSATION_H diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h index e97c1cca3d98d..778d2964b6b1f 100644 --- a/src/server/game/Entities/Creature/GossipDef.h +++ b/src/server/game/Entities/Creature/GossipDef.h @@ -231,11 +231,13 @@ class InteractionData SourceGuid.Clear(); TrainerId = 0; PlayerChoiceId = 0; + IsLaunchedByQuest = false; } ObjectGuid SourceGuid; uint32 TrainerId = 0; uint32 PlayerChoiceId = 0; + bool IsLaunchedByQuest = false; }; class TC_GAME_API PlayerMenu diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 2a8d53e58ea6a..340d91645a318 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9270,7 +9270,7 @@ void Player::SendLoot(Loot& loot, bool aeLooting) SendDirectMessage(packet.Write()); // add 'this' player as one of the players that are looting 'loot' - loot.OnLootOpened(GetMap(), GetGUID()); + loot.OnLootOpened(GetMap(), this); m_AELootView[loot.GetGUID()] = &loot; if (loot.loot_type == LOOT_CORPSE && !loot.GetOwnerGUID().IsItem()) @@ -15460,8 +15460,7 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew // make full db save SaveToDB(false); - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) - SetQuestCompletedBit(questBit, true); + SetQuestCompletedBit(quest_id, true); if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP)) { @@ -15513,8 +15512,7 @@ void Player::SetRewardedQuest(uint32 quest_id) m_RewardedQuests.insert(quest_id); m_RewardedQuestsSave[quest_id] = QUEST_DEFAULT_SAVE_TYPE; - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) - SetQuestCompletedBit(questBit, true); + SetQuestCompletedBit(quest_id, true); } void Player::FailQuest(uint32 questId) @@ -16214,8 +16212,7 @@ void Player::RemoveRewardedQuest(uint32 questId, bool update /*= true*/) m_RewardedQuestsSave[questId] = QUEST_FORCE_DELETE_SAVE_TYPE; } - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId)) - SetQuestCompletedBit(questBit, false); + SetQuestCompletedBit(questId, false); // Remove seasonal quest also Quest const* quest = sObjectMgr->GetQuestTemplate(questId); @@ -16699,8 +16696,9 @@ bool Player::IsQuestCompletedBitSet(uint32 questId) const return (m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_CHARACTER_QUEST_COMPLETED_INDEX].Values[fieldOffset] & flag) != 0; } -void Player::SetQuestCompletedBit(uint32 questBit, bool completed) +void Player::SetQuestCompletedBit(uint32 questId, bool completed) { + uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId); if (!questBit) return; @@ -19665,8 +19663,7 @@ void Player::_LoadQuestStatusRewarded(PreparedQueryResult result) // Skip loading special quests - they are also added to rewarded quests but only once and remain there forever // instead add them separately from load daily/weekly/monthly/seasonal if (!quest->IsDailyOrWeekly() && !quest->IsMonthly() && !quest->IsSeasonal()) - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) - SetQuestCompletedBit(questBit, true); + SetQuestCompletedBit(quest_id, true); for (uint32 i = 0; i < quest->GetRewChoiceItemsCount(); ++i) GetSession()->GetCollectionMgr()->AddItemAppearance(quest->RewardChoiceItemId[i]); @@ -19718,8 +19715,7 @@ void Player::_LoadDailyQuestStatus(PreparedQueryResult result) continue; AddDynamicUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::DailyQuestsCompleted)) = quest_id; - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) - SetQuestCompletedBit(questBit, true); + SetQuestCompletedBit(quest_id, true); TC_LOG_DEBUG("entities.player.loading", "Player::_LoadDailyQuestStatus: Loaded daily quest cooldown (QuestID: {}) for player '{}' ({})", quest_id, GetName(), GetGUID().ToString()); @@ -19745,8 +19741,7 @@ void Player::_LoadWeeklyQuestStatus(PreparedQueryResult result) continue; m_weeklyquests.insert(quest_id); - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) - SetQuestCompletedBit(questBit, true); + SetQuestCompletedBit(quest_id, true); TC_LOG_DEBUG("entities.player.loading", "Player::_LoadWeeklyQuestStatus: Loaded weekly quest cooldown (QuestID: {}) for player '{}' ({})", quest_id, GetName(), GetGUID().ToString()); @@ -19774,8 +19769,7 @@ void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result) continue; m_seasonalquests[event_id][quest_id] = completedTime; - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) - SetQuestCompletedBit(questBit, true); + SetQuestCompletedBit(quest_id, true); TC_LOG_DEBUG("entities.player.loading", "Player::_LoadSeasonalQuestStatus: Loaded seasonal quest cooldown (QuestID: {}) for player '{}' ({})", quest_id, GetName(), GetGUID().ToString()); @@ -19801,8 +19795,7 @@ void Player::_LoadMonthlyQuestStatus(PreparedQueryResult result) continue; m_monthlyquests.insert(quest_id); - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) - SetQuestCompletedBit(questBit, true); + SetQuestCompletedBit(quest_id, true); TC_LOG_DEBUG("entities.player.loading", "Player::_LoadMonthlyQuestStatus: Loaded monthly quest cooldown (QuestID: {}) for player '{}' ({})", quest_id, GetName(), GetGUID().ToString()); @@ -25351,8 +25344,7 @@ void Player::SetMonthlyQuestStatus(uint32 quest_id) void Player::DailyReset() { for (int32 questId : m_activePlayerData->DailyQuestsCompleted) - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId)) - SetQuestCompletedBit(questBit, false); + SetQuestCompletedBit(questId, false); WorldPackets::Quest::DailyQuestsReset dailyQuestsReset; dailyQuestsReset.Count = int32(m_activePlayerData->DailyQuestsCompleted.size()); @@ -25399,8 +25391,7 @@ void Player::ResetWeeklyQuestStatus() return; for (uint32 questId : m_weeklyquests) - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId)) - SetQuestCompletedBit(questBit, false); + SetQuestCompletedBit(questId, false); for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) { @@ -25444,8 +25435,7 @@ void Player::ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime) { if (questItr->second < eventStartTime) { - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questItr->first)) - SetQuestCompletedBit(questBit, false); + SetQuestCompletedBit(questItr->first, false); questItr = eventItr->second.erase(questItr); } @@ -25464,8 +25454,7 @@ void Player::ResetMonthlyQuestStatus() return; for (uint32 questId : m_monthlyquests) - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId)) - SetQuestCompletedBit(questBit, false); + SetQuestCompletedBit(questId, false); m_monthlyquests.clear(); // DB data deleted in caller @@ -26290,7 +26279,7 @@ void Player::UpdateAreaDependentAuras(uint32 newArea) { // use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date if (iter->second->GetSpellInfo()->CheckLocation(GetMapId(), m_zoneUpdateId, newArea, this) != SPELL_CAST_OK) - RemoveOwnedAura(iter); + RemoveOwnedAura(iter, AURA_REMOVE_BY_INTERRUPT); else ++iter; } @@ -26976,6 +26965,9 @@ void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot* case LootItemType::Currency: ModifyCurrency(item->itemid, item->count, CurrencyGainSource::Loot); break; + case LootItemType::TrackingQuest: + // nothing to do, already handled + break; } if (ffaItem) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 0a9e144ab7291..91bec6782a65f 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1721,7 +1721,7 @@ class TC_GAME_API Player final : public Unit, public GridObject void SetQuestSlotObjectiveFlag(uint16 slot, int8 objectiveIndex); void RemoveQuestSlotObjectiveFlag(uint16 slot, int8 objectiveIndex); bool IsQuestCompletedBitSet(uint32 questId) const; - void SetQuestCompletedBit(uint32 questBit, bool completed); + void SetQuestCompletedBit(uint32 questId, bool completed); uint16 GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry) const; void AreaExploredOrEventHappens(uint32 questId); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index ee29aaccc63e2..58b524e8d0df6 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -8259,6 +8259,18 @@ void Unit::Dismount() } } +void Unit::CancelMountAura(bool force) +{ + if (!HasAuraType(SPELL_AURA_MOUNTED)) + return; + + RemoveAurasByType(SPELL_AURA_MOUNTED, [force](AuraApplication const* aurApp) + { + SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo(); + return force || (!spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL) && spellInfo->IsPositive() && !spellInfo->IsPassive()); + }); +} + MountCapabilityEntry const* Unit::GetMountCapability(uint32 mountType) const { if (!mountType) @@ -8361,6 +8373,11 @@ void Unit::UpdateMountCapability() if (IsLoading()) return; + if (SpellShapeshiftFormEntry const* spellShapeshiftForm = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm())) + if (uint32 mountType = spellShapeshiftForm->MountTypeID) + if (!GetMountCapability(mountType)) + CancelTravelShapeshiftForm(AURA_REMOVE_BY_INTERRUPT); + AuraEffectVector mounts = CopyAuraEffectList(GetAuraEffectsByType(SPELL_AURA_MOUNTED)); for (AuraEffect* aurEff : mounts) { @@ -9361,6 +9378,38 @@ void Unit::SetShapeshiftForm(ShapeshiftForm form) SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ShapeshiftForm), form); } +void Unit::CancelShapeshiftForm(bool onlyTravelShapeshiftForm /*= false*/, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/, bool force /*= false*/) +{ + ShapeshiftForm form = GetShapeshiftForm(); + if (form == FORM_NONE) + return; + + bool isTravelShapeshiftForm = [form]() + { + if (SpellShapeshiftFormEntry const* shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form)) + { + if (shapeInfo->MountTypeID) + return true; + + if (shapeInfo->ID == FORM_TRAVEL_FORM || shapeInfo->ID == FORM_AQUATIC_FORM) + return true; + } + + return false; + }(); + + if (onlyTravelShapeshiftForm && !isTravelShapeshiftForm) + return; + + AuraEffectVector shapeshifts = CopyAuraEffectList(GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT)); + for (AuraEffect* aurEff : shapeshifts) + { + SpellInfo const* spellInfo = aurEff->GetBase()->GetSpellInfo(); + if (force || (!spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL) && spellInfo->IsPositive() && !spellInfo->IsPassive())) + aurEff->GetBase()->Remove(removeMode); + } +} + bool Unit::IsInFeralForm() const { ShapeshiftForm form = GetShapeshiftForm(); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 9fd0c7c7310ab..e13e1ebf970d4 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -912,6 +912,7 @@ class TC_GAME_API Unit : public WorldObject void SetCosmeticMountDisplayId(uint32 mountDisplayId) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::CosmeticMountDisplayID), mountDisplayId); } void Mount(uint32 mount, uint32 vehicleId = 0, uint32 creatureEntry = 0); void Dismount(); + void CancelMountAura(bool force = false); MountCapabilityEntry const* GetMountCapability(uint32 mountType) const; void UpdateMountCapability(); @@ -1508,6 +1509,8 @@ class TC_GAME_API Unit : public WorldObject ShapeshiftForm GetShapeshiftForm() const { return ShapeshiftForm(*m_unitData->ShapeshiftForm); } void SetShapeshiftForm(ShapeshiftForm form); + void CancelShapeshiftForm(bool onlyTravelShapeshiftForm = false, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT, bool force = false); + void CancelTravelShapeshiftForm(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT, bool force = false) { CancelShapeshiftForm(true, removeMode, force); }; bool IsInFeralForm() const; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index eca3df6b444db..ab664cbe79607 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -27,6 +27,7 @@ #include "ClientConfigPackets.h" #include "Common.h" #include "Conversation.h" +#include "ConversationAI.h" #include "Corpse.h" #include "DatabaseEnv.h" #include "DB2Stores.h" @@ -1173,7 +1174,10 @@ void WorldSession::HandleCloseInteraction(WorldPackets::Misc::CloseInteraction& if (Creature* creature = _player->GetMap()->GetCreature(closeInteraction.SourceGuid)) creature->SendMirrorSound(_player, 1); #endif - if (_player->PlayerTalkClass->GetInteractionData().SourceGuid == closeInteraction.SourceGuid) + + if (_player->PlayerTalkClass->GetInteractionData().IsLaunchedByQuest) + _player->PlayerTalkClass->GetInteractionData().IsLaunchedByQuest = false; + else if (_player->PlayerTalkClass->GetInteractionData().SourceGuid == closeInteraction.SourceGuid) _player->PlayerTalkClass->GetInteractionData().Reset(); if (_player->GetStableMaster() == closeInteraction.SourceGuid) @@ -1182,8 +1186,8 @@ void WorldSession::HandleCloseInteraction(WorldPackets::Misc::CloseInteraction& void WorldSession::HandleConversationLineStarted(WorldPackets::Misc::ConversationLineStarted& conversationLineStarted) { - if (Conversation* convo = ObjectAccessor::GetConversation(*_player, conversationLineStarted.ConversationGUID)) - sScriptMgr->OnConversationLineStarted(convo, conversationLineStarted.LineID, _player); + if (Conversation* conversation = ObjectAccessor::GetConversation(*_player, conversationLineStarted.ConversationGUID)) + conversation->AI()->OnLineStarted(conversationLineStarted.LineID, _player); } void WorldSession::HandleRequestLatestSplashScreen(WorldPackets::Misc::RequestLatestSplashScreen& /*requestLatestSplashScreen*/) diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index ebf268362b0a4..d25c734c52329 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -197,15 +197,14 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPackets::Quest::QuestG } } - _player->PlayerTalkClass->SendCloseGossip(); - - if (quest->HasFlag(QUEST_FLAGS_LAUNCH_GOSSIP_ACCEPT)) + if (quest->HasFlag(QUEST_FLAGS_LAUNCH_GOSSIP_ACCEPT) && !quest->HasFlagEx(QUEST_FLAGS_EX_SUPPRESS_GOSSIP_ACCEPT)) { auto launchGossip = [&](WorldObject* worldObject) { _player->PlayerTalkClass->ClearMenus(); _player->PrepareGossipMenu(worldObject, _player->GetGossipMenuForSource(worldObject), true); _player->SendPreparedGossip(worldObject); + _player->PlayerTalkClass->GetInteractionData().IsLaunchedByQuest = true; }; if (Creature* creature = object->ToCreature()) @@ -213,6 +212,8 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPackets::Quest::QuestG else if (GameObject* go = object->ToGameObject()) launchGossip(go); } + else + _player->PlayerTalkClass->SendCloseGossip(); return; } diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp index 35fe799915fed..a992e33414c89 100644 --- a/src/server/game/Loot/Loot.cpp +++ b/src/server/game/Loot/Loot.cpp @@ -57,6 +57,10 @@ LootItem::LootItem(LootStoreItem const& li) : itemid(li.itemid), conditions(li.c type = LootItemType::Currency; freeforall = true; break; + case LootStoreItem::Type::TrackingQuest: + type = LootItemType::TrackingQuest; + freeforall = true; + break; default: break; } @@ -77,6 +81,8 @@ bool LootItem::AllowedForPlayer(Player const* player, Loot const* loot) const return ItemAllowedForPlayer(player, loot, itemid, needs_quest, follow_loot_rules, false, conditions); case LootItemType::Currency: return CurrencyAllowedForPlayer(player, itemid, needs_quest, conditions); + case LootItemType::TrackingQuest: + return TrackingQuestAllowedForPlayer(player, itemid, conditions); default: break; } @@ -93,6 +99,8 @@ bool LootItem::AllowedForPlayer(Player const* player, LootStoreItem const& lootS strictUsabilityCheck, lootStoreItem.conditions); case LootStoreItem::Type::Currency: return CurrencyAllowedForPlayer(player, lootStoreItem.itemid, lootStoreItem.needs_quest, lootStoreItem.conditions); + case LootStoreItem::Type::TrackingQuest: + return TrackingQuestAllowedForPlayer(player, lootStoreItem.itemid, lootStoreItem.conditions); default: break; } @@ -177,6 +185,18 @@ bool LootItem::CurrencyAllowedForPlayer(Player const* player, uint32 currencyId, return true; } +bool LootItem::TrackingQuestAllowedForPlayer(Player const* player, uint32 questId, ConditionsReference const& conditions) +{ + // DB conditions check + if (!conditions.Meets(player)) + return false; + + if (player->IsQuestCompletedBitSet(questId)) + return false; + + return true; +} + void LootItem::AddAllowedLooter(Player const* player) { allowedGUIDs.insert(player->GetGUID()); @@ -774,9 +794,9 @@ void Loot::NotifyMoneyRemoved(Map const* map) } } -void Loot::OnLootOpened(Map* map, ObjectGuid looter) +void Loot::OnLootOpened(Map* map, Player* looter) { - AddLooter(looter); + AddLooter(looter->GetGUID()); if (!_wasOpened) { _wasOpened = true; @@ -804,18 +824,20 @@ void Loot::OnLootOpened(Map* map, ObjectGuid looter) } else if (_lootMethod == MASTER_LOOT) { - if (looter == _lootMaster) + if (looter->GetGUID() == _lootMaster) { - if (Player* lootMaster = ObjectAccessor::GetPlayer(map, looter)) - { - WorldPackets::Loot::MasterLootCandidateList masterLootCandidateList; - masterLootCandidateList.LootObj = GetGUID(); - masterLootCandidateList.Players = _allowedLooters; - lootMaster->SendDirectMessage(masterLootCandidateList.Write()); - } + WorldPackets::Loot::MasterLootCandidateList masterLootCandidateList; + masterLootCandidateList.LootObj = GetGUID(); + masterLootCandidateList.Players = _allowedLooters; + looter->SendDirectMessage(masterLootCandidateList.Write()); } } } + + // Flag tracking quests as completed after all items were scanned for this player (some might depend on this quest not being completed) + //if (!_mailUnlootedItems) + if (std::vector* ffaItems = Trinity::Containers::MapGetValuePtr(PlayerFFAItems, looter->GetGUID())) + AutoStoreTrackingQuests(looter, *ffaItems); } bool Loot::HasAllowedLooter(ObjectGuid const& looter) const @@ -866,7 +888,7 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo roundRobinPlayer = lootOwner->GetGUID(); for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) - if (Player const* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter + if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter if (player->IsAtGroupRewardDistance(lootOwner)) FillNotNormalLootFor(player); @@ -939,6 +961,14 @@ void Loot::AddItem(LootStoreItem const& item) items.push_back(generatedLoot); break; } + case LootStoreItem::Type::TrackingQuest: + { + LootItem generatedLoot(item); + generatedLoot.count = 1; + generatedLoot.LootListId = items.size(); + items.push_back(generatedLoot); + break; + } default: break; } @@ -995,6 +1025,11 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool case LootItemType::Currency: player->ModifyCurrency(lootItem->itemid, lootItem->count, CurrencyGainSource::Loot); break; + case LootItemType::TrackingQuest: + + if (Quest const* quest = sObjectMgr->GetQuestTemplate(lootItem->itemid)) + player->RewardQuest(quest, LootItemType::Item, 0, player, false); + break; } if (ffaitem) @@ -1009,6 +1044,20 @@ bool Loot::AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast, bool return allLooted; } +void Loot::AutoStoreTrackingQuests(Player* player, NotNormalLootItemList& ffaItems) +{ + for (NotNormalLootItem& ffaItem : ffaItems) + { + if (items[ffaItem.LootListId].type != LootItemType::TrackingQuest) + continue; + + --unlootedCount; + ffaItem.is_looted = true; + if (Quest const* quest = sObjectMgr->GetQuestTemplate(items[ffaItem.LootListId].itemid)) + player->RewardQuest(quest, LootItemType::Item, 0, player, false); + } +} + void Loot::LootMoney() { gold = 0; @@ -1149,7 +1198,7 @@ void Loot::Update() } } -void Loot::FillNotNormalLootFor(Player const* player) +void Loot::FillNotNormalLootFor(Player* player) { ObjectGuid plguid = player->GetGUID(); _allowedLooters.insert(plguid); @@ -1176,7 +1225,13 @@ void Loot::FillNotNormalLootFor(Player const* player) } if (!ffaItems->empty()) + { + // TODO: flag immediately for loot that is supposed to be mailed if unlooted, otherwise flag when sending SMSG_LOOT_RESPONSE + //if (_mailUnlootedItems) + // AutoStoreTrackingQuests(player, *ffaItems); + PlayerFFAItems[player->GetGUID()] = std::move(ffaItems); + } } // diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h index f29975ebeee70..14b9509a6780b 100644 --- a/src/server/game/Loot/Loot.h +++ b/src/server/game/Loot/Loot.h @@ -212,6 +212,7 @@ struct TC_GAME_API LootItem static bool ItemAllowedForPlayer(Player const* player, Loot const* loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck, ConditionsReference const& conditions); static bool CurrencyAllowedForPlayer(Player const* player, uint32 currencyId, bool needs_quest, ConditionsReference const& conditions); + static bool TrackingQuestAllowedForPlayer(Player const* player, uint32 questId, ConditionsReference const& conditions); void AddAllowedLooter(Player const* player); GuidSet const& GetAllowedLooters() const { return allowedGUIDs; } bool HasAllowedLooter(ObjectGuid const& looter) const; @@ -314,7 +315,7 @@ struct TC_GAME_API Loot void NotifyLootList(Map const* map) const; void NotifyItemRemoved(uint8 lootListId, Map const* map); void NotifyMoneyRemoved(Map const* map); - void OnLootOpened(Map* map, ObjectGuid looter); + void OnLootOpened(Map* map, Player* looter); void AddLooter(ObjectGuid GUID) { PlayersLooting.insert(GUID); } void RemoveLooter(ObjectGuid GUID) { PlayersLooting.erase(GUID); } @@ -322,12 +323,13 @@ struct TC_GAME_API Loot void generateMoneyLoot(uint32 minAmount, uint32 maxAmount); bool FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError = false, uint16 lootMode = LOOT_MODE_DEFAULT, ItemContext context = ItemContext::NONE); - void FillNotNormalLootFor(Player const* player); // count unlooted items + void FillNotNormalLootFor(Player* player); // count unlooted items // Inserts the item into the loot (called by LootTemplate processors) void AddItem(LootStoreItem const& item); bool AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast = false, bool createdByPlayer = false); + void AutoStoreTrackingQuests(Player* player, NotNormalLootItemList& ffaItems); void LootMoney(); LootItem const* GetItemInSlot(uint32 lootListId) const; diff --git a/src/server/game/Loot/LootItemType.h b/src/server/game/Loot/LootItemType.h index 31f0da51787d1..aa1d420295ec5 100644 --- a/src/server/game/Loot/LootItemType.h +++ b/src/server/game/Loot/LootItemType.h @@ -22,8 +22,9 @@ enum class LootItemType : uint8 { - Item = 0, - Currency = 1 + Item = 0, + Currency = 1, + TrackingQuest = 2 }; #endif // LootItemType_h__ diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 0dc6b949c3dc8..ef9ef2ab57287 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -273,6 +273,8 @@ bool LootStoreItem::Roll(bool rate) const return roll_chance_f(chance * qualityModifier); } + case Type::TrackingQuest: + return roll_chance_f(chance); default: break; } @@ -366,6 +368,45 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const } break; } + case Type::TrackingQuest: + { + Quest const* quest = sObjectMgr->GetQuestTemplate(itemid); + if (!quest) + { + TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: quest does not exist - skipped", + store.GetName(), entry, type, itemid); + return false; + } + + if (!quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT)) + { + TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: quest is not a tracking flag - skipped", + store.GetName(), entry, type, itemid); + return false; + } + + if (chance == 0 && groupid == 0) // Zero chance is allowed for grouped entries only + { + TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: equal-chanced grouped entry, but group not defined - skipped", + store.GetName(), entry, type, itemid); + return false; + } + + if (chance != 0 && chance < 0.0001f) // loot with low chance + { + TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: low chance ({}) - skipped", + store.GetName(), entry, type, itemid, chance); + return false; + } + + if (mincount != 1 || maxcount) // wrong count + { + TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} ItemType {} Item {}: tracking quest has count other than 1 (MinCount {} MaxCount {}) - skipped", + store.GetName(), entry, type, itemid, int32(maxcount), mincount); + return false; + } + break; + } default: TC_LOG_ERROR("sql.sql", "Table '{}' Entry {} Item {}: invalid ItemType {}, skipped", @@ -581,6 +622,10 @@ void LootTemplate::CopyConditions(LootItem* li) const if (li->type != LootItemType::Currency) continue; break; + case LootStoreItem::Type::TrackingQuest: + if (li->type != LootItemType::TrackingQuest) + continue; + break; default: break; } @@ -621,6 +666,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId { case LootStoreItem::Type::Item: case LootStoreItem::Type::Currency: + case LootStoreItem::Type::TrackingQuest: // Plain entries (not a reference, not grouped) // Chance is already checked, just add if (!personalLooter || LootItem::AllowedForPlayer(personalLooter, *item, true)) @@ -731,6 +777,7 @@ void LootTemplate::ProcessPersonalLoot(std::unordered_map -class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks +class CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks : public ScriptRegistrySwapHookBase { template @@ -490,6 +491,24 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks "The AI should be null here!"); } + // Hook which is called before a conversation is swapped + static void UnloadResetScript(Conversation* conversation) + { + // Remove deletable events only, + // otherwise it causes crashes with non-deletable spell events. + conversation->m_Events.KillAllEvents(false); + + conversation->AI()->OnRemove(); + } + + static void UnloadDestroyScript(Conversation* conversation) + { + conversation->AI_Destroy(); + + ASSERT(!conversation->AI(), + "The AI should be null here!"); + } + // Hook which is called after a creature was swapped static void LoadInitializeScript(Creature* creature) { @@ -549,6 +568,20 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks at->AI()->OnCreate(nullptr); } + // Hook which is called after a conversation was swapped + static void LoadInitializeScript(Conversation* conversation) + { + ASSERT(!conversation->AI(), + "The AI should be null here!"); + + conversation->AI_Initialize(); + } + + static void LoadResetScript(Conversation* conversation) + { + conversation->AI()->OnCreate(nullptr); + } + static Creature* GetEntityFromMap(std::common_type, Map* map, ObjectGuid const& guid) { return map->GetCreature(guid); @@ -564,6 +597,11 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks return map->GetAreaTrigger(guid); } + static Conversation* GetEntityFromMap(std::common_type, Map* map, ObjectGuid const& guid) + { + return map->GetConversation(guid); + } + static auto VisitObjectsToSwapOnMap(std::unordered_set const& idsToRemove) { return [&idsToRemove](Map* map, auto&& visitor) @@ -737,24 +775,32 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks // This hook is responsible for swapping CreatureAI's template class ScriptRegistrySwapHooks - : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks< + : public CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks< Creature, CreatureScript, Base > { }; // This hook is responsible for swapping GameObjectAI's template class ScriptRegistrySwapHooks - : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks< + : public CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks< GameObject, GameObjectScript, Base > { }; // This hook is responsible for swapping AreaTriggerAI's template class ScriptRegistrySwapHooks - : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks< + : public CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks< AreaTrigger, AreaTriggerEntityScript, Base > { }; +// This hook is responsible for swapping ConversationAI's +template +class ScriptRegistrySwapHooks + : public CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks< + Conversation, ConversationScript, Base + > { +}; + /// This hook is responsible for swapping BattlefieldScripts template class ScriptRegistrySwapHooks @@ -961,7 +1007,7 @@ class SpecializedScriptRegistry friend class ScriptRegistrySwapHooks; template - friend class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks; + friend class CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks; public: SpecializedScriptRegistry() { } @@ -1887,6 +1933,19 @@ bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger, b return entered ? tmpscript->OnTrigger(player, trigger) : tmpscript->OnExit(player, trigger); } +bool ScriptMgr::CanCreateConversationAI(uint32 scriptId) const +{ + return !!ScriptRegistry::Instance()->GetScriptById(scriptId); +} + +ConversationAI* ScriptMgr::GetConversationAI(Conversation* conversation) +{ + ASSERT(conversation); + + GET_SCRIPT_RET(ConversationScript, conversation->GetScriptId(), tmpscript, nullptr); + return tmpscript->GetAI(conversation); +} + Battlefield* ScriptMgr::CreateBattlefield(uint32 scriptId, Map* map) { GET_SCRIPT_RET(BattlefieldScript, scriptId, tmpscript, nullptr); @@ -2733,40 +2792,6 @@ void ScriptMgr::ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& dama FOREACH_SCRIPT(UnitScript)->ModifySpellDamageTaken(target, attacker, damage, spellInfo); } -// Conversation -void ScriptMgr::OnConversationCreate(Conversation* conversation, Unit* creator) -{ - ASSERT(conversation); - - GET_SCRIPT(ConversationScript, conversation->GetScriptId(), tmpscript); - tmpscript->OnConversationCreate(conversation, creator); -} - -void ScriptMgr::OnConversationStart(Conversation* conversation) -{ - ASSERT(conversation); - - GET_SCRIPT(ConversationScript, conversation->GetScriptId(), tmpscript); - tmpscript->OnConversationStart(conversation); -} - -void ScriptMgr::OnConversationLineStarted(Conversation* conversation, uint32 lineId, Player* sender) -{ - ASSERT(conversation); - ASSERT(sender); - - GET_SCRIPT(ConversationScript, conversation->GetScriptId(), tmpscript); - tmpscript->OnConversationLineStarted(conversation, lineId, sender); -} - -void ScriptMgr::OnConversationUpdate(Conversation* conversation, uint32 diff) -{ - ASSERT(conversation); - - GET_SCRIPT(ConversationScript, conversation->GetScriptId(), tmpscript); - tmpscript->OnConversationUpdate(conversation, diff); -} - // Scene void ScriptMgr::OnSceneStart(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate) { @@ -3626,20 +3651,9 @@ ConversationScript::ConversationScript(char const* name) ConversationScript::~ConversationScript() = default; -void ConversationScript::OnConversationCreate(Conversation* /*conversation*/, Unit* /*creator*/) -{ -} - -void ConversationScript::OnConversationStart(Conversation* /*conversation*/ ) -{ -} - -void ConversationScript::OnConversationLineStarted(Conversation* /*conversation*/, uint32 /*lineId*/, Player* /*sender*/) -{ -} - -void ConversationScript::OnConversationUpdate(Conversation* /*conversation*/, uint32 /*diff*/) +ConversationAI* ConversationScript::GetAI(Conversation* /*conversation*/) const { + return nullptr; } SceneScript::SceneScript(char const* name) diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 659048dfa9a6e..0ffe0e3aaa7fe 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -38,6 +38,7 @@ class BattlegroundMap; class BattlegroundScript; class Channel; class Conversation; +class ConversationAI; class Creature; class CreatureAI; class DynamicObject; @@ -948,17 +949,8 @@ class TC_GAME_API ConversationScript : public ScriptObject ~ConversationScript(); - // Called when Conversation is created but not added to Map yet. - virtual void OnConversationCreate(Conversation* conversation, Unit* creator); - - // Called when Conversation is started - virtual void OnConversationStart(Conversation* conversation); - - // Called when player sends CMSG_CONVERSATION_LINE_STARTED with valid conversation guid - virtual void OnConversationLineStarted(Conversation* conversation, uint32 lineId, Player* sender); - - // Called for each update tick - virtual void OnConversationUpdate(Conversation* conversation, uint32 diff); + // Called when a ConversationAI object is needed for the conversation. + virtual ConversationAI* GetAI(Conversation* conversation) const; }; class TC_GAME_API SceneScript : public ScriptObject @@ -1328,10 +1320,8 @@ class TC_GAME_API ScriptMgr public: /* ConversationScript */ - void OnConversationCreate(Conversation* conversation, Unit* creator); - void OnConversationStart(Conversation* conversation); - void OnConversationLineStarted(Conversation* conversation, uint32 lineId, Player* sender); - void OnConversationUpdate(Conversation* conversation, uint32 diff); + bool CanCreateConversationAI(uint32 scriptId) const; + ConversationAI* GetConversationAI(Conversation* conversation); public: /* SceneScript */ @@ -1463,6 +1453,15 @@ class GenericAreaTriggerEntityScript : public AreaTriggerEntityScript }; #define RegisterAreaTriggerAI(ai_name) new GenericAreaTriggerEntityScript(#ai_name) +template +class GenericConversationScript : public ConversationScript +{ +public: + GenericConversationScript(char const* name) : ConversationScript(name) {} + ConversationAI* GetAI(Conversation* conversation) const override { return new AI(conversation); } +}; +#define RegisterConversationAI(ai_name) new GenericConversationScript(#ai_name) + template class GenericBattlegroundMapScript : public BattlegroundMapScript { diff --git a/src/server/scripts/BrokenIsles/zone_mardum.cpp b/src/server/scripts/BrokenIsles/zone_mardum.cpp index 34b604ab7aff8..b4ac35635ba79 100644 --- a/src/server/scripts/BrokenIsles/zone_mardum.cpp +++ b/src/server/scripts/BrokenIsles/zone_mardum.cpp @@ -20,6 +20,7 @@ #include "CellImpl.h" #include "Containers.h" #include "Conversation.h" +#include "ConversationAI.h" #include "CreatureAIImpl.h" #include "EventProcessor.h" #include "GridNotifiersImpl.h" @@ -376,10 +377,10 @@ struct npc_cyana_nightglaive_invasion_begins : public ScriptedAI }; // 922 - The Invasion Begins -class conversation_the_invasion_begins : public ConversationScript +class conversation_the_invasion_begins : public ConversationAI { public: - conversation_the_invasion_begins() : ConversationScript("conversation_the_invasion_begins") { } + conversation_the_invasion_begins(Conversation* conversation) : ConversationAI(conversation) { } enum TheInvasionBeginsConversationData { @@ -396,7 +397,7 @@ class conversation_the_invasion_begins : public ConversationScript EVENT_ILLIDARI_START_PATH }; - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* kaynObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_KAYN_SUNFURY_INVASION_BEGINS, .IgnorePhases = true }); Creature* jayceObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_JAYCE_DARKWEAVER_INVASION_BEGINS, .IgnorePhases = true }); @@ -428,7 +429,7 @@ class conversation_the_invasion_begins : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); @@ -439,7 +440,7 @@ class conversation_the_invasion_begins : public ConversationScript _events.ScheduleEvent(EVENT_ILLIDARI_START_PATH, *illidariStartPathLineStarted); } - static void StartCloneChannel(ObjectGuid guid, Conversation* conversation) + void StartCloneChannel(ObjectGuid guid) { Unit* privateObjectOwner = ObjectAccessor::GetUnit(*conversation, conversation->GetPrivateObjectOwner()); if (!privateObjectOwner) @@ -452,7 +453,7 @@ class conversation_the_invasion_begins : public ConversationScript clone->CastSpell(privateObjectOwner, SPELL_TRACK_TARGET_IN_CHANNEL, false); } - static void StartCloneMovement(ObjectGuid cloneGUID, uint32 pathId, uint32 animKit, Conversation* conversation) + void StartCloneMovement(ObjectGuid cloneGUID, uint32 pathId, uint32 animKit) { Creature* clone = ObjectAccessor::GetCreature(*conversation, cloneGUID); if (!clone) @@ -464,7 +465,7 @@ class conversation_the_invasion_begins : public ConversationScript clone->SetAIAnimKitId(animKit); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -472,12 +473,12 @@ class conversation_the_invasion_begins : public ConversationScript { case EVENT_ILLIDARI_FACE_PLAYERS: { - StartCloneChannel(conversation->GetActorUnit(CONVO_ACTOR_IDX_KAYN)->GetGUID(), conversation); - StartCloneChannel(conversation->GetActorUnit(CONVO_ACTOR_IDX_KORVAS)->GetGUID(), conversation); - StartCloneChannel(_jayceGUID, conversation); - StartCloneChannel(_allariGUID, conversation); - StartCloneChannel(_cyanaGUID, conversation); - StartCloneChannel(_sevisGUID, conversation); + StartCloneChannel(conversation->GetActorUnit(CONVO_ACTOR_IDX_KAYN)->GetGUID()); + StartCloneChannel(conversation->GetActorUnit(CONVO_ACTOR_IDX_KORVAS)->GetGUID()); + StartCloneChannel(_jayceGUID); + StartCloneChannel(_allariGUID); + StartCloneChannel(_cyanaGUID); + StartCloneChannel(_sevisGUID); break; } case EVENT_ILLIDARI_START_PATH: @@ -501,11 +502,11 @@ class conversation_the_invasion_begins : public ConversationScript kaynClone->SetSheath(SHEATH_STATE_MELEE); kaynClone->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); - StartCloneMovement(conversation->GetActorUnit(CONVO_ACTOR_IDX_KORVAS)->GetGUID(), PATH_KORVAS_INVASION_BEGINS, ANIM_DH_RUN, conversation); - StartCloneMovement(_jayceGUID, PATH_JAYCE_INVASION_BEGINS, 0, conversation); - StartCloneMovement(_allariGUID, PATH_ALLARI_INVASION_BEGINS, ANIM_DH_RUN_ALLARI, conversation); - StartCloneMovement(_cyanaGUID, PATH_CYANA_INVASION_BEGINS, 0, conversation); - StartCloneMovement(_sevisGUID, PATH_SEVIS_INVASION_BEGINS, ANIM_DH_RUN, conversation); + StartCloneMovement(conversation->GetActorUnit(CONVO_ACTOR_IDX_KORVAS)->GetGUID(), PATH_KORVAS_INVASION_BEGINS, ANIM_DH_RUN); + StartCloneMovement(_jayceGUID, PATH_JAYCE_INVASION_BEGINS, 0); + StartCloneMovement(_allariGUID, PATH_ALLARI_INVASION_BEGINS, ANIM_DH_RUN_ALLARI); + StartCloneMovement(_cyanaGUID, PATH_CYANA_INVASION_BEGINS, 0); + StartCloneMovement(_sevisGUID, PATH_SEVIS_INVASION_BEGINS, ANIM_DH_RUN); break; } default: @@ -2002,7 +2003,7 @@ void AddSC_zone_mardum() new event_sevis_sacrifice_self(); // Conversation - new conversation_the_invasion_begins(); + RegisterConversationAI(conversation_the_invasion_begins); // Scene new scene_demonhunter_intro(); diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 85e2dc0841242..2e8c825db2bdd 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1187,7 +1187,7 @@ class npc_commandscript : public CommandScript name = itemTemplate->GetName(handler->GetSessionDbcLocale()); if (!name) name = "Unknown item"; - handler->PSendSysMessage(alternateString ? LANG_COMMAND_NPC_SHOWLOOT_ENTRY_2 : LANG_COMMAND_NPC_SHOWLOOT_ENTRY, + handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_ENTRY, alternateString ? 6 : 3 /*number of bytes from following string*/, "\xE2\x94\x80\xE2\x94\x80", itemCount, ItemQualityColors[itemTemplate ? static_cast(itemTemplate->GetQuality()) : ITEM_QUALITY_POOR], itemId, name, itemId); } @@ -1203,6 +1203,23 @@ class npc_commandscript : public CommandScript count, ItemQualityColors[currency ? static_cast(currency->Quality) : ITEM_QUALITY_POOR], currencyId, count, name, currencyId); } + static void _ShowLootTrackingQuestCurrencyEntry(ChatHandler* handler, uint32 questId, bool alternateString = false) + { + Quest const* quest = sObjectMgr->GetQuestTemplate(questId); + std::string_view name; + if (quest) + { + name = quest->GetLogTitle(); + if (handler->GetSessionDbLocaleIndex() != LOCALE_enUS) + if (QuestTemplateLocale const* localeData = sObjectMgr->GetQuestLocale(questId)) + ObjectMgr::GetLocaleString(localeData->LogTitle, handler->GetSessionDbLocaleIndex(), name); + } + if (name.empty()) + name = "Unknown quest"; + handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_TRACKING_QUEST, alternateString ? 6 : 3 /*number of bytes from following string*/, "\xE2\x94\x80\xE2\x94\x80", + questId, STRING_VIEW_FMT_ARG(name), questId); + } + static void _IterateNotNormalLootMap(ChatHandler* handler, NotNormalLootItemMap const& map, std::vector const& items) { for (NotNormalLootItemMap::value_type const& pair : map) @@ -1225,6 +1242,9 @@ class npc_commandscript : public CommandScript case LootItemType::Currency: _ShowLootCurrencyEntry(handler, item.itemid, item.count, true); break; + case LootItemType::TrackingQuest: + _ShowLootTrackingQuestCurrencyEntry(handler, item.itemid, true); + break; } } } @@ -1250,6 +1270,9 @@ class npc_commandscript : public CommandScript case LootItemType::Currency: _ShowLootCurrencyEntry(handler, item.itemid, item.count); break; + case LootItemType::TrackingQuest: + _ShowLootTrackingQuestCurrencyEntry(handler, item.itemid); + break; } } } @@ -1269,6 +1292,9 @@ class npc_commandscript : public CommandScript case LootItemType::Currency: _ShowLootCurrencyEntry(handler, item.itemid, item.count); break; + case LootItemType::TrackingQuest: + _ShowLootTrackingQuestCurrencyEntry(handler, item.itemid); + break; } } } diff --git a/src/server/scripts/DragonIsles/AberrusTheShadowedCrucible/aberrus_the_shadowed_crucible.cpp b/src/server/scripts/DragonIsles/AberrusTheShadowedCrucible/aberrus_the_shadowed_crucible.cpp index 7527b516936eb..746b24a77cad3 100644 --- a/src/server/scripts/DragonIsles/AberrusTheShadowedCrucible/aberrus_the_shadowed_crucible.cpp +++ b/src/server/scripts/DragonIsles/AberrusTheShadowedCrucible/aberrus_the_shadowed_crucible.cpp @@ -18,6 +18,7 @@ #include "AreaTrigger.h" #include "AreaTriggerAI.h" #include "Conversation.h" +#include "ConversationAI.h" #include "InstanceScript.h" #include "MotionMaster.h" #include "ScriptMgr.h" @@ -107,12 +108,12 @@ struct at_aberrus_sarkareth_conversation_intro : AreaTriggerAI }; // 20800 - Conversation -class conversation_aberrus_sabellian_intro : public ConversationScript +class conversation_aberrus_sabellian_intro : public ConversationAI { public: - conversation_aberrus_sabellian_intro() : ConversationScript("conversation_aberrus_sabellian_intro") { } + conversation_aberrus_sabellian_intro(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { if (Milliseconds const* sabellianMoveStartTime = conversation->GetLineStartTime(DEFAULT_LOCALE, CONVO_SABELLIAN_INTRO_LINE_01)) _events.ScheduleEvent(EVENT_SABELLIAN_MOVE, *sabellianMoveStartTime); @@ -121,7 +122,7 @@ class conversation_aberrus_sabellian_intro : public ConversationScript _events.ScheduleEvent(EVENT_SABELLIAN_MOVE_HOME_POS, *sabellianHomeMoveStartTime + Seconds(2)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -157,17 +158,17 @@ class conversation_aberrus_sabellian_intro : public ConversationScript }; // 20985 - Conversation -class conversation_aberrus_kazzara_intro : public ConversationScript +class conversation_aberrus_kazzara_intro : public ConversationAI { public: - conversation_aberrus_kazzara_intro() : ConversationScript("conversation_aberrus_kazzara_intro") { } + conversation_aberrus_kazzara_intro(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { _events.ScheduleEvent(EVENT_KAZZARA_INTRO, conversation->GetLineEndTime(DEFAULT_LOCALE, CONVO_SARKARETH_LAST_LINE)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -213,6 +214,6 @@ void AddSC_aberrus_the_shadowed_crucible() RegisterAreaTriggerAI(at_aberrus_sabellian_conversation_intro); RegisterAreaTriggerAI(at_aberrus_sarkareth_conversation_intro); - new conversation_aberrus_sabellian_intro(); - new conversation_aberrus_kazzara_intro(); + RegisterConversationAI(conversation_aberrus_sabellian_intro); + RegisterConversationAI(conversation_aberrus_kazzara_intro); } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 9c2969e0704f4..ccd5dbe4b7d3f 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -73,6 +73,11 @@ enum UnworthyInitiatePhase PHASE_ATTACKING, }; +enum UnworthyInitiateData +{ + DATA_PRISONER_GUID = 0 +}; + uint32 acherus_soul_prison[12] = { 191577, @@ -191,7 +196,7 @@ class npc_unworthy_initiate : public CreatureScript { if (Creature* anchor = me->FindNearestCreature(29521, 30)) { - anchor->AI()->SetGUID(me->GetGUID()); + anchor->AI()->SetGUID(me->GetGUID(), DATA_PRISONER_GUID); anchor->CastSpell(me, SPELL_SOUL_PRISON_CHAIN, true); anchorGUID = anchor->GetGUID(); } @@ -312,8 +317,11 @@ class npc_unworthy_initiate_anchor : public CreatureScript ObjectGuid prisonerGUID; - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_PRISONER_GUID) + return; + prisonerGUID = guid; } @@ -337,7 +345,7 @@ class go_acherus_soul_prison : public GameObjectScript { if (Creature* anchor = me->FindNearestCreature(29521, 15)) { - ObjectGuid prisonerGUID = anchor->AI()->GetGUID(); + ObjectGuid prisonerGUID = anchor->AI()->GetGUID(DATA_PRISONER_GUID); if (!prisonerGUID.IsEmpty()) if (Creature* prisoner = ObjectAccessor::GetCreature(*player, prisonerGUID)) ENSURE_AI(npc_unworthy_initiate::npc_unworthy_initiateAI, prisoner->AI())->EventStart(anchor, player); diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index 108ce771e0baf..9dce483983b0f 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -88,12 +88,13 @@ enum Action ACTION_REVIVE = 1 }; -enum Misc +enum MandokirMisc { POINT_START_REVIVE = 1, DATA_OHGANOT_SO_FAST = 5762, + DATA_REVIVE_GUID = 0, }; enum SummonGroups @@ -198,7 +199,7 @@ struct boss_mandokir : public BossAI { if (Creature* chainedSpirit = ObjectAccessor::GetCreature(*me, (*itr)->GetGUID())) { - chainedSpirit->AI()->SetGUID(_reviveGUID); + chainedSpirit->AI()->SetGUID(_reviveGUID, DATA_REVIVE_GUID); chainedSpirit->AI()->DoAction(ACTION_REVIVE); _reviveGUID.Clear(); } @@ -219,7 +220,7 @@ struct boss_mandokir : public BossAI return 0; } - void SetGUID(ObjectGuid const& guid, int32 /*type = 0 */) override + void SetGUID(ObjectGuid const& guid, int32 /*type*/) override { _reviveGUID = guid; } @@ -343,7 +344,7 @@ struct npc_chained_spirit : public ScriptedAI _revivePlayerGUID.Clear(); } - void SetGUID(ObjectGuid const& guid, int32 /*type = 0 */) override + void SetGUID(ObjectGuid const& guid, int32 /*type*/) override { _revivePlayerGUID = guid; } @@ -383,7 +384,7 @@ struct npc_chained_spirit : public ScriptedAI if (Creature* mandokir = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MANDOKIR))) { - mandokir->GetAI()->SetGUID(target->GetGUID()); + mandokir->GetAI()->SetGUID(target->GetGUID(), DATA_REVIVE_GUID); mandokir->GetAI()->DoAction(ACTION_START_REVIVE); } diff --git a/src/server/scripts/EasternKingdoms/zone_elwynn_forest.cpp b/src/server/scripts/EasternKingdoms/zone_elwynn_forest.cpp index caa7fb2dd9712..22a8b5dedf208 100644 --- a/src/server/scripts/EasternKingdoms/zone_elwynn_forest.cpp +++ b/src/server/scripts/EasternKingdoms/zone_elwynn_forest.cpp @@ -19,6 +19,7 @@ #include "AreaTriggerAI.h" #include "Containers.h" #include "Conversation.h" +#include "ConversationAI.h" #include "CreatureAIImpl.h" #include "CreatureGroups.h" #include "MotionMaster.h" @@ -469,12 +470,12 @@ struct at_human_heritage_lions_pride_inn_basement_enter : AreaTriggerAI }; // 20342 - Conversation -class conversation_an_unlikely_informant : public ConversationScript +class conversation_an_unlikely_informant : public ConversationAI { public: - conversation_an_unlikely_informant() : ConversationScript("conversation_an_unlikely_informant") { } + conversation_an_unlikely_informant(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* mathiasObject = GetClosestCreatureWithOptions(creator, 15.0f, { .CreatureId = NPC_MATHIAS_SHAW, .IgnorePhases = true }); Creature* vanessaObject = GetClosestCreatureWithOptions(creator, 15.0f, { .CreatureId = NPC_VANESSA_VANCLEEF, .IgnorePhases = true }); @@ -495,7 +496,7 @@ class conversation_an_unlikely_informant : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); @@ -511,7 +512,7 @@ class conversation_an_unlikely_informant : public ConversationScript _events.ScheduleEvent(EVENT_MATHIAS_CLONE_DESPAWN, conversation->GetLastLineEndTime(privateOwnerLocale)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -582,12 +583,12 @@ class conversation_an_unlikely_informant : public ConversationScript }; // 20387 - Conversation -class conversation_the_new_classington_estate : public ConversationScript +class conversation_the_new_classington_estate : public ConversationAI { public: - conversation_the_new_classington_estate() : ConversationScript("conversation_the_new_classington_estate") { } + conversation_the_new_classington_estate(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* mathiasObject = GetClosestCreatureWithOptions(creator, 15.0f, { .CreatureId = NPC_MATHIAS_SHAW, .IgnorePhases = true }); Creature* vanessaObject = GetClosestCreatureWithOptions(creator, 15.0f, { .CreatureId = NPC_VANESSA_VANCLEEF, .IgnorePhases = true }); @@ -608,7 +609,7 @@ class conversation_the_new_classington_estate : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); @@ -622,7 +623,7 @@ class conversation_the_new_classington_estate : public ConversationScript _events.ScheduleEvent(EVENT_MATHIAS_CLONE_DESPAWN, conversation->GetLastLineEndTime(privateOwnerLocale)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -720,8 +721,8 @@ void AddSC_elwynn_forest() RegisterSpellScript(spell_stealth_vanessa_human_heritage); // Conversation - new conversation_an_unlikely_informant(); - new conversation_the_new_classington_estate(); + RegisterConversationAI(conversation_an_unlikely_informant); + RegisterConversationAI(conversation_the_new_classington_estate); // AreaTrigger RegisterAreaTriggerAI(at_human_heritage_lions_pride_inn_basement_enter); diff --git a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp index e071fdf1f1904..902fb016da4bb 100644 --- a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp +++ b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp @@ -19,6 +19,7 @@ #include "AreaTriggerAI.h" #include "Containers.h" #include "Conversation.h" +#include "ConversationAI.h" #include "CreatureAIImpl.h" #include "MotionMaster.h" #include "ObjectAccessor.h" @@ -104,10 +105,10 @@ struct at_stormwind_keep_tides_of_war : AreaTriggerAI Position const VisionOfSailorsMemoryPosition = { -8384.131f, 324.383f, 148.443f, 1.559973f }; // 4857 - Conversation -class conversation_start_council_tides_of_war : public ConversationScript +class conversation_start_council_tides_of_war : public ConversationAI { public: - conversation_start_council_tides_of_war() : ConversationScript("conversation_start_council_tides_of_war") { } + conversation_start_council_tides_of_war(Conversation* conversation) : ConversationAI(conversation) { } enum Events { @@ -123,7 +124,7 @@ class conversation_start_council_tides_of_war : public ConversationScript CONVO_LINE_JAINA_CREDIT = 19486, }; - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* jainaObject = GetClosestCreatureWithOptions(creator, 30.0f, { .CreatureId = NPC_JAINA_TIDES_OF_WAR, .IgnorePhases = true }); if (!jainaObject) @@ -137,7 +138,7 @@ class conversation_start_council_tides_of_war : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); @@ -147,7 +148,7 @@ class conversation_start_council_tides_of_war : public ConversationScript _events.ScheduleEvent(EVENT_KILL_CREDIT, conversation->GetLineEndTime(privateOwnerLocale, CONVO_LINE_JAINA_CREDIT)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -422,10 +423,10 @@ struct npc_lysande_starshade_ancient_curses : public ScriptedAI }; // 22025 - Conversation -class conversation_quest_ancient_curses_accept : public ConversationScript +class conversation_quest_ancient_curses_accept : public ConversationAI { public: - conversation_quest_ancient_curses_accept() : ConversationScript("conversation_quest_ancient_curses_accept") { } + conversation_quest_ancient_curses_accept(Conversation* conversation) : ConversationAI(conversation) { } enum AncientCursesConversationEvents { @@ -439,7 +440,7 @@ class conversation_quest_ancient_curses_accept : public ConversationScript CONVO_LINE_LYSANDER_START_PATH = 60113, }; - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* arkonarinObject = GetClosestCreatureWithOptions(creator, 20.0f, { .CreatureId = NPC_ARKONARIN_STARSHADE, .IgnorePhases = true }); Creature* lysanderObject = GetClosestCreatureWithOptions(creator, 20.0f, { .CreatureId = NPC_LYSANDER_STARSHADE, .IgnorePhases = true }); @@ -461,7 +462,7 @@ class conversation_quest_ancient_curses_accept : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); @@ -472,7 +473,7 @@ class conversation_quest_ancient_curses_accept : public ConversationScript _events.ScheduleEvent(EVENT_LYSANDER_START_PATH, *lysanderPathStartTime); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -563,8 +564,8 @@ void AddSC_stormwind_city() RegisterCreatureAI(npc_lysande_starshade_ancient_curses); // Conversation - new conversation_start_council_tides_of_war(); - new conversation_quest_ancient_curses_accept(); + RegisterConversationAI(conversation_start_council_tides_of_war); + RegisterConversationAI(conversation_quest_ancient_curses_accept); // PlayerScript new player_conv_after_movie_tides_of_war(); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp index c44c56bb0f1dc..2889c7e4e0549 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp @@ -85,7 +85,8 @@ enum InnEventLines enum InnEventMisc { DATA_REQUEST_FACING = 0, - DATA_REACHED_WP = 1 + DATA_REACHED_WP = 1, + DATA_INVOKING_PLAYER_GUID, }; class npc_hearthsinger_forresten_cot : public CreatureScript @@ -158,8 +159,11 @@ class npc_hearthsinger_forresten_cot : public CreatureScript } // Player has hit the Belfast stairs areatrigger, we are taking him over for a moment - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_INVOKING_PLAYER_GUID) + return; + if (_hadBelfast) return; _hadBelfast = true; @@ -226,7 +230,7 @@ class at_stratholme_inn_stairs_cot : public AreaTriggerScript if (instance->GetData(DATA_INSTANCE_PROGRESS) <= CRATES_IN_PROGRESS) // Forrest's script will handle Belfast for this, since SmartAI lacks the features to do it (we can't pass a custom target) if (Creature* forrest = player->FindNearestCreature(NPC_FORREST, 200.0f, true)) - forrest->AI()->SetGUID(player->GetGUID()); + forrest->AI()->SetGUID(player->GetGUID(), DATA_INVOKING_PLAYER_GUID); return true; } }; diff --git a/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp index fc9e400c7a082..b59e43a4075f9 100644 --- a/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp +++ b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp @@ -218,7 +218,7 @@ struct boss_baleroc : public firelands_bossAI firelands_bossAI::UpdateAI(diff); } - void SetGUID(ObjectGuid const& guid, int32 type = 0) override + void SetGUID(ObjectGuid const& guid, int32 type) override { switch (type) { diff --git a/src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.cpp b/src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.cpp index d8973eb29e72a..21fb2e722fcd3 100644 --- a/src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.cpp +++ b/src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.cpp @@ -18,6 +18,7 @@ #include "AreaTrigger.h" #include "AreaTriggerAI.h" #include "Conversation.h" +#include "ConversationAI.h" #include "Creature.h" #include "InstanceScript.h" #include "Map.h" @@ -351,12 +352,12 @@ class spell_waycrest_manor_organ_missiles : public SpellScript // 267597 - Waycrest Manor - Waycrests Defeated (Alliance) // 7351 - Conversation // 7352 - Conversation -class conversation_waycrest_manor_waycrests_defeated : public ConversationScript +class conversation_waycrest_manor_waycrests_defeated : public ConversationAI { public: - conversation_waycrest_manor_waycrests_defeated() : ConversationScript("conversation_waycrest_manor_waycrests_defeated") { } + conversation_waycrest_manor_waycrests_defeated(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { if (Milliseconds const* gorakTulMoveStartTimeAlliance = conversation->GetLineStartTime(DEFAULT_LOCALE, CONVERSATION_LINE_LUCILLE_WAYCREST)) _events.ScheduleEvent(EVENT_GORAK_TUL_TRANSFORM, *gorakTulMoveStartTimeAlliance); @@ -364,7 +365,7 @@ class conversation_waycrest_manor_waycrests_defeated : public ConversationScript _events.ScheduleEvent(EVENT_GORAK_TUL_TRANSFORM, *gorakTulMoveStartTimeHorde + 3s); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -442,5 +443,5 @@ void AddSC_waycrest_manor() // Lord and Lady Waycrest outro RegisterAreaTriggerAI(at_waycrest_manor_organ_missiles); RegisterSpellScript(spell_waycrest_manor_organ_missiles); - new conversation_waycrest_manor_waycrests_defeated(); + RegisterConversationAI(conversation_waycrest_manor_waycrests_defeated); } diff --git a/src/server/scripts/KulTiras/zone_boralus.cpp b/src/server/scripts/KulTiras/zone_boralus.cpp index 32dc694211072..854e8e0298f95 100644 --- a/src/server/scripts/KulTiras/zone_boralus.cpp +++ b/src/server/scripts/KulTiras/zone_boralus.cpp @@ -19,6 +19,7 @@ #include "AreaTriggerAI.h" #include "Containers.h" #include "Conversation.h" +#include "ConversationAI.h" #include "CreatureAIImpl.h" #include "MotionMaster.h" #include "ObjectAccessor.h" @@ -138,12 +139,12 @@ struct npc_taelia_get_your_bearings : public ScriptedAI }; // 5360 - Conversation -class conversation_boralus_hub_tour_00 : public ConversationScript +class conversation_boralus_hub_tour_00 : public ConversationAI { public: - conversation_boralus_hub_tour_00() : ConversationScript("conversation_boralus_hub_tour_00") { } + conversation_boralus_hub_tour_00(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* kultiranGuard = creator->FindNearestCreatureWithOptions(20.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = creator->GetGUID() }); if (!kultiranGuard) @@ -174,10 +175,10 @@ struct at_boralus_get_your_bearings : AreaTriggerAI }; // 5362 - Conversation - Get your Bearings (Ferry) -class conversation_boralus_hub_tour : public ConversationScript +class conversation_boralus_hub_tour : public ConversationAI { public: - conversation_boralus_hub_tour(char const* scriptName) : ConversationScript(scriptName) { } + conversation_boralus_hub_tour(Conversation* conversation) : ConversationAI(conversation) { } enum ConversationFerryData { @@ -187,7 +188,7 @@ class conversation_boralus_hub_tour : public ConversationScript virtual Position const& GetGuardMovePosition() = 0; virtual uint32 GetKillCreditId() = 0; - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* kultiranGuard = creator->FindNearestCreatureWithOptions(20.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = creator->GetGUID() }); if (!kultiranGuard) @@ -200,14 +201,14 @@ class conversation_boralus_hub_tour : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); _events.ScheduleEvent(EVENT_TAELIA_CREDIT, conversation->GetLastLineEndTime(privateOwnerLocale)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -241,7 +242,7 @@ Position const TaeliaFerryPos = { 1039.5955f, -598.00653f, 1.458778f }; class conversation_boralus_hub_tour_ferry : public conversation_boralus_hub_tour { public: - conversation_boralus_hub_tour_ferry() : conversation_boralus_hub_tour("conversation_boralus_hub_tour_ferry") { } + conversation_boralus_hub_tour_ferry(Conversation* conversation) : conversation_boralus_hub_tour(conversation) { } Position const& GetGuardMovePosition() { @@ -260,7 +261,7 @@ Position const TaeliaBankPos = { 1118.7385f, -622.4115f, 17.76035f }; class conversation_boralus_hub_tour_counting_house : public conversation_boralus_hub_tour { public: - conversation_boralus_hub_tour_counting_house() : conversation_boralus_hub_tour("conversation_boralus_hub_tour_counting_house") { } + conversation_boralus_hub_tour_counting_house(Conversation* conversation) : conversation_boralus_hub_tour(conversation) { } Position const& GetGuardMovePosition() { @@ -279,7 +280,7 @@ Position const TaeliaInnPos = { 1177.39f, -587.682f, 31.557224f }; class conversation_boralus_hub_tour_harbor_inn : public conversation_boralus_hub_tour { public: - conversation_boralus_hub_tour_harbor_inn() : conversation_boralus_hub_tour("conversation_boralus_hub_tour_harbor_inn") { } + conversation_boralus_hub_tour_harbor_inn(Conversation* conversation) : conversation_boralus_hub_tour(conversation) { } Position const& GetGuardMovePosition() { @@ -298,7 +299,7 @@ Position const TaeliaFlightMasterPos = { 1149.82f, -471.071f, 30.503826f }; class conversation_boralus_hub_tour_flight_master : public conversation_boralus_hub_tour { public: - conversation_boralus_hub_tour_flight_master() : conversation_boralus_hub_tour("conversation_boralus_hub_tour_flight_master") { } + conversation_boralus_hub_tour_flight_master(Conversation* conversation) : conversation_boralus_hub_tour(conversation) {} Position const& GetGuardMovePosition() { @@ -312,12 +313,12 @@ class conversation_boralus_hub_tour_flight_master : public conversation_boralus_ }; // 9556 - Conversation The Old Knight (accept Quest) -class conversation_boralus_accept_old_knight : public ConversationScript +class conversation_boralus_accept_old_knight : public ConversationAI { public: - conversation_boralus_accept_old_knight() : ConversationScript("conversation_boralus_accept_old_knight") { } + conversation_boralus_accept_old_knight(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* kultiranGuard = creator->FindNearestCreatureWithOptions(20.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = creator->GetGUID() }); if (!kultiranGuard) @@ -344,12 +345,12 @@ struct at_boralus_old_knight_enter_harbormasters_office : AreaTriggerAI }; // 7605 - Conversation The Old Knight (Enter the Harbormasters Office) -class conversation_boralus_enter_harbormaster_office : public ConversationScript +class conversation_boralus_enter_harbormaster_office : public ConversationAI { public: - conversation_boralus_enter_harbormaster_office() : ConversationScript("conversation_boralus_enter_harbormaster_office") { } + conversation_boralus_enter_harbormaster_office(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* kultiranGuard = creator->FindNearestCreatureWithOptions(20.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = creator->GetGUID() }); if (!kultiranGuard) @@ -428,10 +429,10 @@ Position const GreyguardOneOfficePos = { 1044.979f, -468.523f, 8.386f, 6.03047f Position const GreyguardTwoOfficePos = { 1042.359f, -467.738f, 8.386f, 6.04665f }; // 8062 - Conversation -class conversation_boralus_cyrus_meets_genn : public ConversationScript +class conversation_boralus_cyrus_meets_genn : public ConversationAI { public: - conversation_boralus_cyrus_meets_genn() : ConversationScript("conversation_boralus_cyrus_meets_genn") { } + conversation_boralus_cyrus_meets_genn(Conversation* conversation) : ConversationAI(conversation) { } enum OldKnightsConversationData { @@ -440,7 +441,7 @@ class conversation_boralus_cyrus_meets_genn : public ConversationScript EVENT_OLD_KNIGHTS_CLONE_DESPAWN = 1 }; - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* cyrusObject = GetClosestCreatureWithOptions(creator, 30.0f, { .CreatureId = NPC_CYRUS_CRESTFALL, .IgnorePhases = true }); Creature* gennObject = GetClosestCreatureWithOptions(creator, 30.0f, { .CreatureId = NPC_GENN_GREYMANE, .IgnorePhases = true }); @@ -470,14 +471,14 @@ class conversation_boralus_cyrus_meets_genn : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); _events.ScheduleEvent(EVENT_OLD_KNIGHTS_CLONE_DESPAWN, conversation->GetLineEndTime(privateOwnerLocale, CONVO_LINE_CYRUS_AND_GENN_DESPAWN)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -532,10 +533,10 @@ Position const CyrusMoveToOfficeFirePos = { 1075.257f, -487.25696f, 9.812291f }; Position const CyrusStaticOfficePos = { 1071.428f, -486.312f, 9.783f, 3.4995f }; // 7653 - Conversation -class conversation_cyrus_crestfall_shaking_hands : public ConversationScript +class conversation_cyrus_crestfall_shaking_hands : public ConversationAI { public: - conversation_cyrus_crestfall_shaking_hands() : ConversationScript("conversation_cyrus_crestfall_shaking_hands") { } + conversation_cyrus_crestfall_shaking_hands(Conversation* conversation) : ConversationAI(conversation) { } enum ShakingHandsConversationData { @@ -553,7 +554,7 @@ class conversation_cyrus_crestfall_shaking_hands : public ConversationScript POINT_CYRUS_MOVE_BACK_TO_GENN = 2 }; - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { Creature* cyrusObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_CYRUS_CRESTFALL, .IgnorePhases = true }); if (!cyrusObject) @@ -569,7 +570,7 @@ class conversation_cyrus_crestfall_shaking_hands : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); @@ -579,7 +580,7 @@ class conversation_cyrus_crestfall_shaking_hands : public ConversationScript _events.ScheduleEvent(EVENT_CYRUS_DESPAWN_CLONE_OFFICE, conversation->GetLineEndTime(privateOwnerLocale, CONVO_LINE_CYRUS_DESPAWN_CLONE_OFFICE)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -778,15 +779,15 @@ void AddSC_zone_boralus() RegisterCreatureAI(npc_7th_legion_magus_sanctum_of_the_sages); // Conversation - new conversation_boralus_hub_tour_00(); - new conversation_boralus_hub_tour_ferry(); - new conversation_boralus_hub_tour_counting_house(); - new conversation_boralus_hub_tour_harbor_inn(); - new conversation_boralus_hub_tour_flight_master(); - new conversation_boralus_accept_old_knight(); - new conversation_boralus_enter_harbormaster_office(); - new conversation_boralus_cyrus_meets_genn(); - new conversation_cyrus_crestfall_shaking_hands(); + RegisterConversationAI(conversation_boralus_hub_tour_00); + RegisterConversationAI(conversation_boralus_hub_tour_ferry); + RegisterConversationAI(conversation_boralus_hub_tour_counting_house); + RegisterConversationAI(conversation_boralus_hub_tour_harbor_inn); + RegisterConversationAI(conversation_boralus_hub_tour_flight_master); + RegisterConversationAI(conversation_boralus_accept_old_knight); + RegisterConversationAI(conversation_boralus_enter_harbormaster_office); + RegisterConversationAI(conversation_boralus_cyrus_meets_genn); + RegisterConversationAI(conversation_cyrus_crestfall_shaking_hands); // Scene new scene_boralus_client_scene_cyrus_and_genn(); diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp index 5694682b7bdad..637dc68e499ce 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp @@ -54,7 +54,9 @@ enum PrinceTaldaramMisc { DATA_EMBRACE_DMG = 20000, H_DATA_EMBRACE_DMG = 40000, - SUMMON_GROUP_CONTROLLERS = 1 + SUMMON_GROUP_CONTROLLERS = 1, + + DATA_FLAME_SPHERE_TARGET_GUID = 0, }; enum PrinceTaldaramYells @@ -123,7 +125,7 @@ struct boss_prince_taldaram : public BossAI case NPC_FLAME_SPHERE_1: case NPC_FLAME_SPHERE_2: case NPC_FLAME_SPHERE_3: - summon->AI()->SetGUID(_flameSphereTargetGUID); + summon->AI()->SetGUID(_flameSphereTargetGUID, DATA_FLAME_SPHERE_TARGET_GUID); break; case NPC_JEDOGA_CONTROLLER: summon->CastSpell(me, SPELL_BEAM_VISUAL); @@ -307,8 +309,11 @@ struct npc_prince_taldaram_flame_sphere : public ScriptedAI _events.ScheduleEvent(EVENT_DESPAWN, 13s); } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_FLAME_SPHERE_TARGET_GUID) + return; + _flameSphereTargetGUID = guid; } diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp index 9a295622a7bea..f0ee0c58f960d 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp @@ -116,7 +116,8 @@ enum Data { DATA_CRUSHER_PACK_ID = 1, DATA_HADRONOX_ENTERED_COMBAT, - DATA_HADRONOX_WEBBED_DOORS + DATA_HADRONOX_WEBBED_DOORS, + DATA_ANUBAR_GUID, }; enum Creatures @@ -264,8 +265,11 @@ struct boss_hadronox : public BossAI nerubian->DespawnOrUnsummon(); } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_ANUBAR_GUID) + return; + _anubar.push_back(guid); } @@ -664,7 +668,7 @@ struct npc_hadronox_foeAI : public ScriptedAI { ScriptedAI::InitializeAI(); if (Creature* hadronox = _instance->GetCreature(DATA_HADRONOX)) - hadronox->AI()->SetGUID(me->GetGUID()); + hadronox->AI()->SetGUID(me->GetGUID(), DATA_ANUBAR_GUID); } void MovementInform(uint32 type, uint32 id) override diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index 0d9673d354bb8..be50f9066d48a 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -179,7 +179,8 @@ enum Misc DATA_MATERIAL_DAMAGE_TAKEN = 2, DATA_STACKS_DISPELLED = 3, DATA_FIGHT_PHASE = 4, - DATA_SPAWNED_FLAMES = 5 + DATA_SPAWNED_FLAMES = 5, + DATA_ROOT_GUID = 6, }; enum OrbCarrierSeats @@ -1110,7 +1111,7 @@ class npc_meteor_strike : public CreatureScript { Position pos = me->GetNearPosition(5.0f, frand(-static_cast(M_PI / 6.0f), static_cast(M_PI / 6.0f))); if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25s)) - flame->AI()->SetGUID(me->GetGUID()); + flame->AI()->SetGUID(me->GetGUID(), DATA_ROOT_GUID); } } @@ -1139,8 +1140,11 @@ class npc_meteor_strike_flame : public CreatureScript SetCombatMovement(false); } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_ROOT_GUID) + return; + _rootOwnerGuid = guid; _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(800)); } @@ -1170,7 +1174,7 @@ class npc_meteor_strike_flame : public CreatureScript Position pos = me->GetNearPosition(5.0f, frand(-static_cast(M_PI / 6.0f), static_cast(M_PI / 6.0f))); if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25s)) - flame->AI()->SetGUID(_rootOwnerGuid); + flame->AI()->SetGUID(_rootOwnerGuid, DATA_ROOT_GUID); } void EnterEvadeMode(EvadeReason /*why*/) override { } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index ccbed6d6e3146..0ca2b57d1eb96 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -170,7 +170,8 @@ enum Misc SUMMON_PRINCES_GROUP = 1, DATA_INTRO = 2, DATA_INTRO_DONE = 3, - DATA_PRINCE_EVADE = 4 + DATA_PRINCE_EVADE = 4, + DATA_CHASE_TARGET_GUID = 5, }; class StandUpEvent : public BasicEvent @@ -698,7 +699,7 @@ struct boss_prince_taldaram_icc : public BloodPrincesBossAI Talk(EMOTE_TALDARAM_FLAME, target); if (target) - summon->AI()->SetGUID(target->GetGUID()); + summon->AI()->SetGUID(target->GetGUID(), DATA_CHASE_TARGET_GUID); } void UpdateAI(uint32 diff) override @@ -930,8 +931,11 @@ struct npc_ball_of_flame : public ScriptedAI } } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_CHASE_TARGET_GUID) + return; + _chaseGUID = guid; } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index b6948a05f508d..b28d92a4175ef 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -166,6 +166,11 @@ enum Actions ACTION_START_INTRO }; +enum LadyDeathwhisperData +{ + DATA_VENGEFUL_SHADE_TARGET_GUID = 0 +}; + #define NPC_DARNAVAN RAID_MODE(NPC_DARNAVAN_10, NPC_DARNAVAN_25, NPC_DARNAVAN_10, NPC_DARNAVAN_25) #define NPC_DARNAVAN_CREDIT RAID_MODE(NPC_DARNAVAN_CREDIT_10, NPC_DARNAVAN_CREDIT_25, NPC_DARNAVAN_CREDIT_10, NPC_DARNAVAN_CREDIT_25) #define QUEST_DEPROGRAMMING RAID_MODE(QUEST_DEPROGRAMMING_10, QUEST_DEPROGRAMMING_25, QUEST_DEPROGRAMMING_10, QUEST_DEPROGRAMMING_25) @@ -477,7 +482,7 @@ struct boss_lady_deathwhisper : public BossAI case NPC_VENGEFUL_SHADE: if (_nextVengefulShadeTargetGUID.empty()) break; - summon->AI()->SetGUID(_nextVengefulShadeTargetGUID.front()); + summon->AI()->SetGUID(_nextVengefulShadeTargetGUID.front(), DATA_VENGEFUL_SHADE_TARGET_GUID); _nextVengefulShadeTargetGUID.pop_front(); break; case NPC_CULT_ADHERENT: @@ -782,8 +787,11 @@ struct npc_vengeful_shade : public ScriptedAI }); } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_VENGEFUL_SHADE_TARGET_GUID) + return; + _targetGUID = guid; } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index b723602872537..9de7dea9523f4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -291,7 +291,7 @@ struct boss_lord_marrowgar : public BossAI return &_coldflameLastPos; } - ObjectGuid GetGUID(int32 type /*= 0 */) const override + ObjectGuid GetGUID(int32 type) const override { switch (type) { 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 a4cf8553ea9bf..a8eac473250d7 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -358,13 +358,11 @@ enum MiscData SOUND_PAIN = 17360, // separate sound, not attached to any text EQUIP_ASHBRINGER_GLOWING = 50442, - EQUIP_BROKEN_FROSTMOURNE = 50840 -}; + EQUIP_BROKEN_FROSTMOURNE = 50840, -enum Misc -{ DATA_PLAGUE_STACK = 70337, DATA_VILE = 45814622, + DATA_GRABBED_PLAYER_GUID = 0, GOSSIP_MENU_START_INTRO = 10993 }; @@ -1500,8 +1498,11 @@ struct npc_valkyr_shadowguard : public ScriptedAI } } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_GRABBED_PLAYER_GUID) + return; + _grabbedPlayer = guid; } @@ -2304,7 +2305,7 @@ class spell_the_lich_king_valkyr_target_search : public SpellScript _target = Trinity::Containers::SelectRandomContainerElement(targets); targets.clear(); targets.push_back(_target); - GetCaster()->GetAI()->SetGUID(_target->GetGUID()); + GetCaster()->GetAI()->SetGUID(_target->GetGUID(), DATA_GRABBED_PLAYER_GUID); } void ReplaceTarget(std::list& targets) diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index 7a2b208929b08..9aa6f4d263632 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -69,6 +69,11 @@ enum Events EVENT_SUMMON, }; +enum MaexxnaData +{ + DATA_WEBWRAP_VICTIM_GUID = 0 +}; + const float WEB_WRAP_MOVE_SPEED = 20.0f; struct WebTargetSelector @@ -143,7 +148,7 @@ struct boss_maexxna : public BossAI target->RemoveAura(SPELL_WEB_SPRAY); if (Creature* wrap = DoSummon(NPC_WEB_WRAP, WrapPositions[wrapPos], 70s, TEMPSUMMON_TIMED_DESPAWN)) { - wrap->AI()->SetGUID(target->GetGUID()); // handles application of debuff + wrap->AI()->SetGUID(target->GetGUID(), DATA_WEBWRAP_VICTIM_GUID); // handles application of debuff target->GetMotionMaster()->MoveJump(WrapPositions[wrapPos], WEB_WRAP_MOVE_SPEED, WEB_WRAP_MOVE_SPEED); // move after stun to avoid stun cancelling move } } @@ -188,10 +193,14 @@ struct npc_webwrap : public NullCreatureAI me->SetVisible(false); } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_WEBWRAP_VICTIM_GUID) + return; + if (!guid) return; + victimGUID = guid; if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID)) { diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index 1bdff8f8adfcf..b4ac065ce14e6 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -1260,7 +1260,9 @@ enum BloodsporeRuination NPC_BLOODMAGE_LAURITH = 25381, SAY_BLOODMAGE_LAURITH = 0, EVENT_TALK = 1, - EVENT_RESET_ORIENTATION + EVENT_RESET_ORIENTATION, + + DATA_FACING_PLAYER_GUID = 0 }; // 45997 - Bloodspore Ruination @@ -1270,7 +1272,7 @@ class spell_q11719_bloodspore_ruination_45997 : public SpellScript { if (Unit* caster = GetCaster()) if (Creature* laurith = caster->FindNearestCreature(NPC_BLOODMAGE_LAURITH, 100.0f)) - laurith->AI()->SetGUID(caster->GetGUID()); + laurith->AI()->SetGUID(caster->GetGUID(), DATA_FACING_PLAYER_GUID); } void Register() override @@ -1289,8 +1291,11 @@ struct npc_bloodmage_laurith : public ScriptedAI _playerGUID.Clear(); } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + void SetGUID(ObjectGuid const& guid, int32 id) override { + if (id != DATA_FACING_PLAYER_GUID) + return; + if (!_playerGUID.IsEmpty()) return; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp index 4db5d93b6e66d..0c6aa3f1fb5ce 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp @@ -102,7 +102,7 @@ struct npc_inner_demon : public ScriptedAI victimGUID = guid; } - ObjectGuid GetGUID(int32 id/* = 0 */) const override + ObjectGuid GetGUID(int32 id) const override { if (id == INNER_DEMON_VICTIM) return victimGUID; diff --git a/src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp b/src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp index 4ed74a7b144da..c54d4a7d8fa51 100644 --- a/src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp +++ b/src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp @@ -18,6 +18,7 @@ #include "AreaTrigger.h" #include "AreaTriggerAI.h" #include "Conversation.h" +#include "ConversationAI.h" #include "CreatureAI.h" #include "CreatureAIImpl.h" #include "InstanceScript.h" @@ -262,12 +263,12 @@ struct at_sylvanas_windrunner_introduction : AreaTriggerAI }; // 17368 - Sylvanas Windrunner's Introduction (Conversation) -class conversation_sylvanas_windrunner_introduction : public ConversationScript +class conversation_sylvanas_windrunner_introduction : public ConversationAI { public: - conversation_sylvanas_windrunner_introduction() : ConversationScript("conversation_sylvanas_windrunner_introduction") { } + conversation_sylvanas_windrunner_introduction(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationCreate(Conversation* conversation, Unit* creator) override + void OnCreate(Unit* creator) override { InstanceScript* instance = creator->GetInstanceScript(); if (!instance) @@ -283,7 +284,7 @@ class conversation_sylvanas_windrunner_introduction : public ConversationScript _events.ScheduleEvent(EVENT_INTRODUCTION, 5s + 500ms); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -485,5 +486,5 @@ void AddSC_boss_sylvanas_windrunner() RegisterAreaTriggerAI(at_sylvanas_windrunner_z_check); RegisterAreaTriggerAI(at_sylvanas_windrunner_introduction); - new conversation_sylvanas_windrunner_introduction(); + RegisterConversationAI(conversation_sylvanas_windrunner_introduction); } diff --git a/src/server/scripts/Shadowlands/SepulcherOfTheFirstOnes/boss_anduin_wrynn.cpp b/src/server/scripts/Shadowlands/SepulcherOfTheFirstOnes/boss_anduin_wrynn.cpp index 62f6ca3f78bca..aba4b171ef4a2 100644 --- a/src/server/scripts/Shadowlands/SepulcherOfTheFirstOnes/boss_anduin_wrynn.cpp +++ b/src/server/scripts/Shadowlands/SepulcherOfTheFirstOnes/boss_anduin_wrynn.cpp @@ -776,14 +776,14 @@ struct boss_anduin_wrynn : public BossAI if (!jaina) return; - Conversation* convo = Conversation::CreateConversation(CONVERSATION_INTRO, me, me->GetPosition(), ObjectGuid::Empty, nullptr, false); - if (!convo) + Conversation* conversation = Conversation::CreateConversation(CONVERSATION_INTRO, me, me->GetPosition(), ObjectGuid::Empty, nullptr, false); + if (!conversation) return; - convo->AddActor(NPC_UTHER_THE_LIGHTBRINGER_ANDUIN, 1, uther->GetGUID()); - convo->AddActor(NPC_SYLVANAS_WINDRUNNER_ANDUIN, 2, sylvanas->GetGUID()); - convo->AddActor(NPC_LADY_JAINA_PROUDMOORE_ANDUIN, 3, jaina->GetGUID()); - convo->Start(); + conversation->AddActor(NPC_UTHER_THE_LIGHTBRINGER_ANDUIN, 1, uther->GetGUID()); + conversation->AddActor(NPC_SYLVANAS_WINDRUNNER_ANDUIN, 2, sylvanas->GetGUID()); + conversation->AddActor(NPC_LADY_JAINA_PROUDMOORE_ANDUIN, 3, jaina->GetGUID()); + conversation->Start(); }); scheduler.Schedule(35s, [this](TaskContext /*task*/) @@ -827,15 +827,15 @@ struct boss_anduin_wrynn : public BossAI firim->GetMotionMaster()->MovePath(PATH_OUTRODUCTION_FIRIM, false); - Conversation* convo = Conversation::CreateConversation(CONVERSATION_ANDUIN_OUTRODUCTION, me, me->GetPosition(), ObjectGuid::Empty, nullptr, false); - if (!convo) + Conversation* conversation = Conversation::CreateConversation(CONVERSATION_ANDUIN_OUTRODUCTION, me, me->GetPosition(), ObjectGuid::Empty, nullptr, false); + if (!conversation) break; - convo->AddActor(NPC_LADY_JAINA_PROUDMOORE_ANDUIN, 1, jaina->GetGUID()); - convo->AddActor(NPC_SYLVANAS_WINDRUNNER_ANDUIN, 2, sylvanas->GetGUID()); - convo->AddActor(NPC_UTHER_THE_LIGHTBRINGER_ANDUIN, 3, uther->GetGUID()); - convo->AddActor(NPC_FIRIM_ANDUIN, 4, firim->GetGUID()); - convo->Start(); + conversation->AddActor(NPC_LADY_JAINA_PROUDMOORE_ANDUIN, 1, jaina->GetGUID()); + conversation->AddActor(NPC_SYLVANAS_WINDRUNNER_ANDUIN, 2, sylvanas->GetGUID()); + conversation->AddActor(NPC_UTHER_THE_LIGHTBRINGER_ANDUIN, 3, uther->GetGUID()); + conversation->AddActor(NPC_FIRIM_ANDUIN, 4, firim->GetGUID()); + conversation->Start(); break; } case ACTION_ARTHAS_INTERMISSION_UTHER: @@ -843,10 +843,10 @@ struct boss_anduin_wrynn : public BossAI instance->DoUpdateWorldState(WORLD_STATE_ANDUIN_INTERMISSION, 1); if (Creature* uther = instance->GetCreature(DATA_UTHER_THE_LIGHTBRINGER_ANDUIN)) { - if (Conversation* convo = Conversation::CreateConversation(CONVERSATION_ARTHAS_UTHER, me, me->GetPosition(), ObjectGuid::Empty, nullptr, false)) + if (Conversation* conversation = Conversation::CreateConversation(CONVERSATION_ARTHAS_UTHER, me, me->GetPosition(), ObjectGuid::Empty, nullptr, false)) { - convo->AddActor(NPC_UTHER_THE_LIGHTBRINGER_ANDUIN, 1, uther->GetGUID()); - convo->Start(); + conversation->AddActor(NPC_UTHER_THE_LIGHTBRINGER_ANDUIN, 1, uther->GetGUID()); + conversation->Start(); } } break; @@ -856,10 +856,10 @@ struct boss_anduin_wrynn : public BossAI instance->DoUpdateWorldState(WORLD_STATE_ANDUIN_INTERMISSION, 2); if (Creature* sylvanas = instance->GetCreature(DATA_SYLVANAS_WINDRUNNER_ANDUIN)) { - if (Conversation* convo = Conversation::CreateConversation(CONVERSATION_ARTHAS_SYLVANAS, me, me->GetPosition(), ObjectGuid::Empty, nullptr, false)) + if (Conversation* conversation = Conversation::CreateConversation(CONVERSATION_ARTHAS_SYLVANAS, me, me->GetPosition(), ObjectGuid::Empty, nullptr, false)) { - convo->AddActor(NPC_SYLVANAS_WINDRUNNER_ANDUIN, 1, sylvanas->GetGUID()); - convo->Start(); + conversation->AddActor(NPC_SYLVANAS_WINDRUNNER_ANDUIN, 1, sylvanas->GetGUID()); + conversation->Start(); } } break; diff --git a/src/server/scripts/World/conversation_scripts.cpp b/src/server/scripts/World/conversation_scripts.cpp index 507da020e79c0..f1a442c40b791 100644 --- a/src/server/scripts/World/conversation_scripts.cpp +++ b/src/server/scripts/World/conversation_scripts.cpp @@ -17,9 +17,10 @@ #include "ScriptMgr.h" #include "Conversation.h" +#include "ConversationAI.h" #include "Player.h" -class conversation_allied_race_dk_defender_of_azeroth : public ConversationScript +class conversation_allied_race_dk_defender_of_azeroth : public ConversationAI { public: enum DefenderOfAzerothIds : uint32 @@ -30,15 +31,15 @@ class conversation_allied_race_dk_defender_of_azeroth : public ConversationScrip CONVERSATION_LINE_PLAYER = 32926 }; - conversation_allied_race_dk_defender_of_azeroth() : ConversationScript("conversation_allied_race_dk_defender_of_azeroth") { } + conversation_allied_race_dk_defender_of_azeroth(Conversation* conversation) : ConversationAI(conversation) { } - void OnConversationCreate(Conversation* /*conversation*/, Unit* creator) override + void OnCreate(Unit* creator) override { if (Player* player = creator->ToPlayer()) player->KilledMonsterCredit(NPC_TALK_TO_YOUR_COMMANDER_CREDIT); } - void OnConversationLineStarted(Conversation* /*conversation*/, uint32 lineId, Player* sender) override + void OnLineStarted(uint32 lineId, Player* sender) override { if (lineId != CONVERSATION_LINE_PLAYER) return; @@ -49,5 +50,5 @@ class conversation_allied_race_dk_defender_of_azeroth : public ConversationScrip void AddSC_conversation_scripts() { - new conversation_allied_race_dk_defender_of_azeroth(); + RegisterConversationAI(conversation_allied_race_dk_defender_of_azeroth); } diff --git a/src/server/scripts/Zandalar/KingsRest/kings_rest.cpp b/src/server/scripts/Zandalar/KingsRest/kings_rest.cpp index 00d545b3d3f34..5ffa6554ebceb 100644 --- a/src/server/scripts/Zandalar/KingsRest/kings_rest.cpp +++ b/src/server/scripts/Zandalar/KingsRest/kings_rest.cpp @@ -18,6 +18,7 @@ #include "AreaTrigger.h" #include "AreaTriggerAI.h" #include "Conversation.h" +#include "ConversationAI.h" #include "GameObject.h" #include "GameObjectAI.h" #include "InstanceScript.h" @@ -85,10 +86,10 @@ struct at_kings_rest_trigger_intro_event_with_zul : AreaTriggerAI }; // 7690 - Shadow of Zul - KingsRest Intro -class conversation_kings_rest_intro : public ConversationScript +class conversation_kings_rest_intro : public ConversationAI { public: - conversation_kings_rest_intro() : ConversationScript("conversation_kings_rest_intro") { } + conversation_kings_rest_intro(Conversation* conversation) : ConversationAI(conversation) { } enum KingsRestIntroConversationData { @@ -103,7 +104,7 @@ class conversation_kings_rest_intro : public ConversationScript EVENT_ZUL_INTRO_DESPAWN, }; - void OnConversationCreate(Conversation* conversation, Unit* /*creator*/) override + void OnCreate(Unit* /*creator*/) override { TempSummon* shadowOfZul = conversation->SummonCreature(NPC_SHADOW_OF_ZUL, ShadowOfZulIntroSpawnPosition, TEMPSUMMON_MANUAL_DESPAWN); if (!shadowOfZul) @@ -113,12 +114,12 @@ class conversation_kings_rest_intro : public ConversationScript conversation->Start(); } - void OnConversationStart(Conversation* conversation) override + void OnStart() override { _events.ScheduleEvent(EVENT_ZUL_OPEN_INTRO_DOOR, conversation->GetLineEndTime(DEFAULT_LOCALE, CONVO_LINE_INTRO_DOOR)); } - void OnConversationUpdate(Conversation* conversation, uint32 diff) override + void OnUpdate(uint32 diff) override { _events.Update(diff); @@ -595,7 +596,7 @@ void AddSC_kings_rest() RegisterAreaTriggerAI(at_kings_rest_gust_slash); // Conversation - new conversation_kings_rest_intro(); + RegisterConversationAI(conversation_kings_rest_intro); // Spells RegisterSpellScript(spell_kings_rest_suppression_slam);