aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorModoX <moardox@gmail.com>2024-12-28 23:25:10 +0100
committerOvahlord <dreadkiller@gmx.de>2024-12-29 12:16:46 +0100
commit1f81c961f24337abdc8de25bd23d9834d0c7392b (patch)
tree46b4699d0b3ffbc4b197913064659abd978d1ed3 /src
parent9b49b9009d010b56b0289e8122bedceb172e4948 (diff)
Core/AI: Implemented conversation ai (#30538)
(cherry picked from commit 309ba22a15e5e0b4321b99f7157ccb18e0adc8dd) # Conflicts: # src/server/scripts/BrokenIsles/zone_mardum.cpp # src/server/scripts/DragonIsles/AberrusTheShadowedCrucible/aberrus_the_shadowed_crucible.cpp # src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp # src/server/scripts/KulTiras/WaycrestManor/waycrest_manor.cpp # src/server/scripts/KulTiras/zone_boralus.cpp # src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp # src/server/scripts/Shadowlands/SepulcherOfTheFirstOnes/boss_anduin_wrynn.cpp # src/server/scripts/Zandalar/KingsRest/kings_rest.cpp
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/CoreAI/ConversationAI.cpp28
-rw-r--r--src/server/game/AI/CoreAI/ConversationAI.h73
-rw-r--r--src/server/game/AI/CreatureAISelector.cpp27
-rw-r--r--src/server/game/AI/CreatureAISelector.h4
-rw-r--r--src/server/game/Entities/Conversation/Conversation.cpp24
-rw-r--r--src/server/game/Entities/Conversation/Conversation.h7
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp5
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp118
-rw-r--r--src/server/game/Scripting/ScriptMgr.h29
-rw-r--r--src/server/scripts/EasternKingdoms/zone_elwynn_forest.cpp25
-rw-r--r--src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp13
-rw-r--r--src/server/scripts/World/conversation_scripts.cpp11
12 files changed, 269 insertions, 95 deletions
diff --git a/src/server/game/AI/CoreAI/ConversationAI.cpp b/src/server/game/AI/CoreAI/ConversationAI.cpp
new file mode 100644
index 00000000000..19de90c6ad2
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 00000000000..25adc8bc68b
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 = 0) 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; }
+
+ // 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/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp
index c6a8871a822..ec22e9e4eba 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 0cb6c9632b3..d2ee805706f 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/Entities/Conversation/Conversation.cpp b/src/server/game/Entities/Conversation/Conversation.cpp
index 2f0aa4ee82d..1578db33a8b 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"
@@ -59,6 +61,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<Conversation>(GetGUID());
}
@@ -66,7 +70,7 @@ void Conversation::RemoveFromWorld()
void Conversation::Update(uint32 diff)
{
- sScriptMgr->OnConversationUpdate(this, diff);
+ _ai->OnUpdate(diff);
if (GetDuration() > Milliseconds(diff))
_duration -= Milliseconds(diff);
@@ -173,6 +177,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)
@@ -216,7 +222,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()
@@ -244,7 +250,7 @@ bool Conversation::Start()
if (!GetMap()->AddToMap(this))
return false;
- sScriptMgr->OnConversationStart(this);
+ _ai->OnStart();
return true;
}
@@ -331,6 +337,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 3719038e138..5d84b1818d3 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<Con
Unit* GetActorUnit(uint32 actorIdx) const;
Creature* GetActorCreature(uint32 actorIdx) const;
+ void AI_Initialize();
+ void AI_Destroy();
+
+ ConversationAI* AI() { return _ai.get(); }
uint32 GetScriptId() const;
UF::UpdateField<UF::ConversationData, 0, TYPEID_CONVERSATION> m_conversationData;
@@ -97,6 +102,8 @@ class TC_GAME_API Conversation final : public WorldObject, public GridObject<Con
std::unordered_map<std::pair<LocaleConstant /*locale*/, int32 /*lineId*/>, Milliseconds /*startTime*/> _lineStartTimes;
std::array<Milliseconds /*endTime*/, TOTAL_LOCALES> _lastLineEndTimes;
+
+ std::unique_ptr<ConversationAI> _ai;
};
#endif // TRINITYCORE_CONVERSATION_H
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 5c013da0770..679d95a46b8 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"
@@ -1159,8 +1160,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::HandleQueryCountdownTimer(WorldPackets::Misc::QueryCountdownTimer& queryCountdownTimer)
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index e69b64a73fa..99f25980a0d 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -21,6 +21,7 @@
#include "AreaTriggerAI.h"
#include "ChatCommand.h"
#include "Conversation.h"
+#include "ConversationAI.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
@@ -382,7 +383,7 @@ public:
/// This hook is responsible for swapping Creature, GameObject and AreaTrigger AI's
template<typename ObjectType, typename ScriptType, typename Base>
-class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks
+class CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks
: public ScriptRegistrySwapHookBase
{
template<typename W>
@@ -484,6 +485,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)
{
@@ -543,6 +562,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<Creature>, Map* map, ObjectGuid const& guid)
{
return map->GetCreature(guid);
@@ -558,6 +591,11 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks
return map->GetAreaTrigger(guid);
}
+ static Conversation* GetEntityFromMap(std::common_type<Conversation>, Map* map, ObjectGuid const& guid)
+ {
+ return map->GetConversation(guid);
+ }
+
static auto VisitObjectsToSwapOnMap(std::unordered_set<uint32> const& idsToRemove)
{
return [&idsToRemove](Map* map, auto&& visitor)
@@ -731,24 +769,32 @@ private:
// This hook is responsible for swapping CreatureAI's
template<typename Base>
class ScriptRegistrySwapHooks<CreatureScript, Base>
- : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks<
+ : public CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks<
Creature, CreatureScript, Base
> { };
// This hook is responsible for swapping GameObjectAI's
template<typename Base>
class ScriptRegistrySwapHooks<GameObjectScript, Base>
- : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks<
+ : public CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks<
GameObject, GameObjectScript, Base
> { };
// This hook is responsible for swapping AreaTriggerAI's
template<typename Base>
class ScriptRegistrySwapHooks<AreaTriggerEntityScript, Base>
- : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks<
+ : public CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks<
AreaTrigger, AreaTriggerEntityScript, Base
> { };
+// This hook is responsible for swapping ConversationAI's
+template<typename Base>
+class ScriptRegistrySwapHooks<ConversationScript, Base>
+ : public CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks<
+ Conversation, ConversationScript, Base
+ > {
+};
+
/// This hook is responsible for swapping BattlefieldScripts
template<typename Base>
class ScriptRegistrySwapHooks<BattlefieldScript, Base>
@@ -955,7 +1001,7 @@ class SpecializedScriptRegistry<ScriptType, true>
friend class ScriptRegistrySwapHooks;
template<typename, typename, typename>
- friend class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks;
+ friend class CreatureGameObjectAreaTriggerConversationScriptRegistrySwapHooks;
public:
SpecializedScriptRegistry() { }
@@ -1752,6 +1798,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<ConversationScript>::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);
@@ -2279,40 +2338,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)
{
@@ -3172,20 +3197,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 31a5842a383..d7746b01e04 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;
@@ -911,17 +912,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
@@ -1279,10 +1271,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 */
@@ -1405,6 +1395,15 @@ class GenericAreaTriggerEntityScript : public AreaTriggerEntityScript
};
#define RegisterAreaTriggerAI(ai_name) new GenericAreaTriggerEntityScript<ai_name>(#ai_name)
+template <class AI>
+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>(#ai_name)
+
template<class Script>
class GenericBattlegroundMapScript : public BattlegroundMapScript
{
diff --git a/src/server/scripts/EasternKingdoms/zone_elwynn_forest.cpp b/src/server/scripts/EasternKingdoms/zone_elwynn_forest.cpp
index caa7fb2dd97..22a8b5dedf2 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 @@ public:
conversation->Start();
}
- void OnConversationStart(Conversation* conversation) override
+ void OnStart() override
{
LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale();
@@ -511,7 +512,7 @@ public:
_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 @@ private:
};
// 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 @@ public:
conversation->Start();
}
- void OnConversationStart(Conversation* conversation) override
+ void OnStart() override
{
LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale();
@@ -622,7 +623,7 @@ public:
_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 7cb4ed0d3d7..0b828c2c87e 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"
@@ -94,10 +95,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
{
@@ -113,7 +114,7 @@ public:
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)
@@ -127,7 +128,7 @@ public:
conversation->Start();
}
- void OnConversationStart(Conversation* conversation) override
+ void OnStart() override
{
LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale();
@@ -137,7 +138,7 @@ public:
_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);
@@ -332,7 +333,7 @@ void AddSC_stormwind_city()
RegisterCreatureAI(npc_anduin_wrynn_nation_of_kultiras);
// Conversation
- new conversation_start_council_tides_of_war();
+ RegisterConversationAI(conversation_start_council_tides_of_war);
// PlayerScript
new player_conv_after_movie_tides_of_war();
diff --git a/src/server/scripts/World/conversation_scripts.cpp b/src/server/scripts/World/conversation_scripts.cpp
index 507da020e79..f1a442c40b7 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 @@ public:
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 @@ public:
void AddSC_conversation_scripts()
{
- new conversation_allied_race_dk_defender_of_azeroth();
+ RegisterConversationAI(conversation_allied_race_dk_defender_of_azeroth);
}