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);