aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp4
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h2
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/DataStores/DB2LoadInfo.h21
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp2
-rw-r--r--src/server/game/DataStores/DB2Stores.h1
-rw-r--r--src/server/game/DataStores/DB2Structure.h13
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp3
-rw-r--r--src/server/game/Entities/Conversation/Conversation.cpp157
-rw-r--r--src/server/game/Entities/Conversation/Conversation.h91
-rw-r--r--src/server/game/Entities/Object/Object.cpp4
-rw-r--r--src/server/game/Entities/Object/Object.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp1
-rw-r--r--src/server/game/Globals/ConversationDataStore.cpp181
-rw-r--r--src/server/game/Globals/ConversationDataStore.h65
-rw-r--r--src/server/game/Globals/ObjectAccessor.cpp9
-rw-r--r--src/server/game/Globals/ObjectAccessor.h1
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp2
-rw-r--r--src/server/game/Globals/ObjectMgr.h1
-rw-r--r--src/server/game/Grids/GridDefines.h9
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.cpp2
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h14
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiersImpl.h50
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp3
-rw-r--r--src/server/game/Grids/ObjectGridLoader.h1
-rw-r--r--src/server/game/Maps/Map.cpp11
-rw-r--r--src/server/game/Maps/Map.h1
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h2
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp14
-rw-r--r--src/server/game/Spells/SpellInfo.cpp2
-rw-r--r--src/server/game/World/World.cpp4
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp25
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp10
-rw-r--r--src/server/shared/Dynamic/TypeList.h13
35 files changed, 709 insertions, 16 deletions
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index da134a3d9b0..99f01a91a5b 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -185,6 +185,10 @@ void HotfixDatabaseConnection::DoPrepareStatements()
PrepareStatement(HOTFIX_SEL_CINEMATIC_SEQUENCES, "SELECT ID, SoundID, Camera1, Camera2, Camera3, Camera4, Camera5, Camera6, Camera7, Camera8"
" FROM cinematic_sequences ORDER BY ID DESC", CONNECTION_SYNCH);
+ // ConversationLine.db2
+ PrepareStatement(HOTFIX_SEL_CONVERSATION_LINE, "SELECT ID, BroadcastTextID, SpellVisualKitID, Duration, NextLineID, Unk1, Yell, Unk2, Unk3"
+ " FROM conversation_line ORDER BY ID DESC", CONNECTION_SYNCH);
+
// CreatureDisplayInfo.db2
PrepareStatement(HOTFIX_SEL_CREATURE_DISPLAY_INFO, "SELECT ID, CreatureModelScale, ModelID, NPCSoundID, SizeClass, Flags, Gender, "
"ExtendedDisplayInfoID, TextureVariation1, TextureVariation2, TextureVariation3, PortraitTextureFileDataID, CreatureModelAlpha, SoundID, "
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h
index 4e53630805f..06710712818 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.h
+++ b/src/server/database/Database/Implementation/HotfixDatabase.h
@@ -116,6 +116,8 @@ enum HotfixDatabaseStatements : uint32
HOTFIX_SEL_CINEMATIC_SEQUENCES,
+ HOTFIX_SEL_CONVERSATION_LINE,
+
HOTFIX_SEL_CREATURE_DISPLAY_INFO,
HOTFIX_SEL_CREATURE_DISPLAY_INFO_EXTRA,
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 425d0e96ccc..7eb60a6a34c 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -757,6 +757,8 @@ enum RBACPermissions
RBAC_PERM_COMMAND_RELOAD_SCENE_TEMPLATE = 850,
RBAC_PERM_COMMAND_RELOAD_AREATRIGGER_TEMPLATE = 851,
RBAC_PERM_COMMAND_GO_OFFSET = 852,
+ RBAC_PERM_COMMAND_RELOAD_CONVERSATION_TEMPLATE = 853,
+ RBAC_PERM_COMMAND_DEBUG_CONVERSATION = 854,
// custom permissions 1000+
RBAC_PERM_MAX
diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h
index 53398f8f4e1..91ea862d1fc 100644
--- a/src/server/game/DataStores/DB2LoadInfo.h
+++ b/src/server/game/DataStores/DB2LoadInfo.h
@@ -818,6 +818,27 @@ struct CinematicSequencesLoadInfo
}
};
+struct ConversationLineLoadInfo
+{
+ static DB2LoadInfo const* Instance()
+ {
+ static DB2FieldMeta const fields[] =
+ {
+ { false, FT_INT, "ID" },
+ { false, FT_INT, "BroadcastTextID" },
+ { false, FT_INT, "SpellVisualKitID" },
+ { false, FT_INT, "Duration" },
+ { false, FT_SHORT, "NextLineID" },
+ { false, FT_SHORT, "Unk1" },
+ { false, FT_BYTE, "Yell" },
+ { false, FT_BYTE, "Unk2" },
+ { false, FT_BYTE, "Unk3" },
+ };
+ static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, ConversationLineMeta::Instance(), HOTFIX_SEL_CONVERSATION_LINE);
+ return &loadInfo;
+ }
+};
+
struct CreatureDisplayInfoLoadInfo
{
static DB2LoadInfo const* Instance()
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index c62dd2ee9b8..4eb4742da45 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -65,6 +65,7 @@ DB2Storage<ChrRacesEntry> sChrRacesStore("ChrRaces.db2", C
DB2Storage<ChrSpecializationEntry> sChrSpecializationStore("ChrSpecialization.db2", ChrSpecializationLoadInfo::Instance());
DB2Storage<CinematicCameraEntry> sCinematicCameraStore("CinematicCamera.db2", CinematicCameraLoadInfo::Instance());
DB2Storage<CinematicSequencesEntry> sCinematicSequencesStore("CinematicSequences.db2", CinematicSequencesLoadInfo::Instance());
+DB2Storage<ConversationLineEntry> sConversationLineStore("ConversationLine.db2", ConversationLineLoadInfo::Instance());
DB2Storage<CreatureDisplayInfoEntry> sCreatureDisplayInfoStore("CreatureDisplayInfo.db2", CreatureDisplayInfoLoadInfo::Instance());
DB2Storage<CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore("CreatureDisplayInfoExtra.db2", CreatureDisplayInfoExtraLoadInfo::Instance());
DB2Storage<CreatureFamilyEntry> sCreatureFamilyStore("CreatureFamily.db2", CreatureFamilyLoadInfo::Instance());
@@ -361,6 +362,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sChrSpecializationStore);
LOAD_DB2(sCinematicCameraStore);
LOAD_DB2(sCinematicSequencesStore);
+ LOAD_DB2(sConversationLineStore);
LOAD_DB2(sCreatureDisplayInfoStore);
LOAD_DB2(sCreatureDisplayInfoExtraStore);
LOAD_DB2(sCreatureFamilyStore);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 2970bb56965..8bc6acb986d 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -64,6 +64,7 @@ TC_GAME_API extern DB2Storage<ChrRacesEntry> sChrRacesSto
TC_GAME_API extern DB2Storage<ChrSpecializationEntry> sChrSpecializationStore;
TC_GAME_API extern DB2Storage<CinematicCameraEntry> sCinematicCameraStore;
TC_GAME_API extern DB2Storage<CinematicSequencesEntry> sCinematicSequencesStore;
+TC_GAME_API extern DB2Storage<ConversationLineEntry> sConversationLineStore;
TC_GAME_API extern DB2Storage<CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
TC_GAME_API extern DB2Storage<CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore;
TC_GAME_API extern DB2Storage<CreatureFamilyEntry> sCreatureFamilyStore;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 459ed14beae..ec141cb062a 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -475,6 +475,19 @@ struct CinematicSequencesEntry
uint16 Camera[8];
};
+struct ConversationLineEntry
+{
+ uint32 ID;
+ uint32 BroadcastTextID;
+ uint32 SpellVisualKitID;
+ uint32 Duration;
+ uint16 NextLineID;
+ uint16 Unk1;
+ uint8 Yell;
+ uint8 Unk2;
+ uint8 Unk3;
+};
+
struct CreatureDisplayInfoEntry
{
uint32 ID;
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
index 99e343cc948..3ea350a583b 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
@@ -202,8 +202,7 @@ void AreaTrigger::Remove()
_ai->OnRemove();
- RemoveFromWorld();
- AddObjectToRemoveList();
+ AddObjectToRemoveList(); // calls RemoveFromWorld
}
}
diff --git a/src/server/game/Entities/Conversation/Conversation.cpp b/src/server/game/Entities/Conversation/Conversation.cpp
new file mode 100644
index 00000000000..8e422937d57
--- /dev/null
+++ b/src/server/game/Entities/Conversation/Conversation.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 "Unit.h"
+#include "UpdateData.h"
+
+Conversation::Conversation() : WorldObject(false), _duration(0)
+{
+ m_objectType |= TYPEMASK_CONVERSATION;
+ m_objectTypeId = TYPEID_CONVERSATION;
+
+ m_updateFlag = UPDATEFLAG_STATIONARY_POSITION;
+
+ m_valuesCount = CONVERSATION_END;
+ _dynamicValuesCount = CONVERSATION_DYNAMIC_END;
+}
+
+Conversation::~Conversation()
+{
+}
+
+void Conversation::AddToWorld()
+{
+ ///- Register the Conversation for guid lookup and for caster
+ if (!IsInWorld())
+ {
+ GetMap()->GetObjectsStore().Insert<Conversation>(GetGUID(), this);
+ WorldObject::AddToWorld();
+ }
+}
+
+void Conversation::RemoveFromWorld()
+{
+ ///- Remove the Conversation from the accessor and from all lists of objects in world
+ if (IsInWorld())
+ {
+ WorldObject::RemoveFromWorld();
+ GetMap()->GetObjectsStore().Remove<Conversation>(GetGUID());
+ }
+}
+
+bool Conversation::IsNeverVisibleFor(WorldObject const* seer) const
+{
+ if (_participants.find(seer->GetGUID()) == _participants.end())
+ return true;
+
+ return WorldObject::IsNeverVisibleFor(seer);
+}
+
+void Conversation::Update(uint32 diff)
+{
+ if (GetDuration() > int32(diff))
+ _duration -= diff;
+ else
+ Remove(); // expired
+
+ WorldObject::Update(diff);
+}
+
+void Conversation::Remove()
+{
+ if (IsInWorld())
+ {
+ AddObjectToRemoveList(); // calls RemoveFromWorld
+ }
+}
+
+Conversation* Conversation::CreateConversation(uint32 conversationEntry, Unit* creator, Position const& pos, GuidUnorderedSet&& participants, SpellInfo const* spellInfo /*= nullptr*/)
+{
+ ConversationTemplate const* conversationTemplate = sConversationDataStore->GetConversationTemplate(conversationEntry);
+ if (!conversationTemplate)
+ return nullptr;
+
+ ObjectGuid::LowType lowGuid = creator->GetMap()->GenerateLowGuid<HighGuid::Conversation>();
+
+ Conversation* conversation = new Conversation();
+ if (!conversation->Create(lowGuid, conversationEntry, creator->GetMap(), creator, pos, std::move(participants), spellInfo))
+ {
+ delete conversation;
+ return nullptr;
+ }
+
+ return conversation;
+}
+
+bool Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry, Map* map, Unit* creator, Position const& pos, GuidUnorderedSet&& participants, SpellInfo const* /*spellInfo = nullptr*/)
+{
+ ConversationTemplate const* conversationTemplate = sConversationDataStore->GetConversationTemplate(conversationEntry);
+ ASSERT(conversationTemplate);
+
+ _creatorGuid = creator->GetGUID();
+ _participants = std::move(participants);
+
+ SetMap(map);
+ Relocate(pos);
+
+ Object::_Create(ObjectGuid::Create<HighGuid::Conversation>(GetMapId(), conversationEntry, lowGuid));
+ SetPhaseMask(creator->GetPhaseMask(), false);
+ CopyPhaseFrom(creator);
+
+ SetEntry(conversationEntry);
+ SetObjectScale(1.0f);
+
+ SetUInt32Value(CONVERSATION_LAST_LINE_END_TIME, conversationTemplate->LastLineEndTime);
+ _duration = conversationTemplate->LastLineEndTime;
+
+ uint16 actorsIndex = 0;
+ for (ConversationActorTemplate const* actor : conversationTemplate->Actors)
+ {
+ if (actor)
+ {
+ ConversationDynamicFieldActor actorField;
+ actorField.ActorTemplate = *actor;
+ actorField.Type = ConversationDynamicFieldActor::ActorType::CreatureActor;
+ SetDynamicStructuredValue(CONVERSATION_DYNAMIC_FIELD_ACTORS, actorsIndex++, &actorField);
+ }
+ else
+ ++actorsIndex;
+ }
+
+ uint16 linesIndex = 0;
+ for (ConversationLineTemplate const* line : conversationTemplate->Lines)
+ SetDynamicStructuredValue(CONVERSATION_DYNAMIC_FIELD_LINES, linesIndex++, line);
+
+ if (!GetMap()->AddToMap(this))
+ return false;
+
+ return true;
+}
+
+void Conversation::AddActor(ObjectGuid const& actorGuid, uint16 actorIdx)
+{
+ ConversationDynamicFieldActor actorField;
+ actorField.ActorGuid = actorGuid;
+ actorField.Type = ConversationDynamicFieldActor::ActorType::WorldObjectActor;
+ SetDynamicStructuredValue(CONVERSATION_DYNAMIC_FIELD_ACTORS, actorIdx, &actorField);
+}
+
+void Conversation::AddParticipant(ObjectGuid const& participantGuid)
+{
+ _participants.insert(participantGuid);
+}
diff --git a/src/server/game/Entities/Conversation/Conversation.h b/src/server/game/Entities/Conversation/Conversation.h
new file mode 100644
index 00000000000..7b168704f10
--- /dev/null
+++ b/src/server/game/Entities/Conversation/Conversation.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 TRINITYCORE_CONVERSATION_H
+#define TRINITYCORE_CONVERSATION_H
+
+#include "Object.h"
+#include "ConversationDataStore.h"
+
+class Unit;
+class SpellInfo;
+
+struct ConversationDynamicFieldActor
+{
+ ConversationDynamicFieldActor() : Type(0), Padding(0)
+ {
+ memset(Raw.Data, 0, sizeof(Raw.Data));
+ }
+
+ enum ActorType
+ {
+ WorldObjectActor = 0,
+ CreatureActor = 1
+ };
+
+ union
+ {
+ ObjectGuid ActorGuid;
+
+ ConversationActorTemplate ActorTemplate;
+
+ struct
+ {
+ uint32 Data[4];
+ } Raw;
+ };
+
+ uint32 Type;
+ uint32 Padding;
+};
+
+class TC_GAME_API Conversation : public WorldObject, public GridObject<Conversation>
+{
+ public:
+ Conversation();
+ ~Conversation();
+
+ void AddToWorld() override;
+ void RemoveFromWorld() override;
+
+ bool IsNeverVisibleFor(WorldObject const* seer) const override;
+
+ void Update(uint32 diff) override;
+ void Remove();
+ int32 GetDuration() const { return _duration; }
+
+ static Conversation* CreateConversation(uint32 conversationEntry, Unit* creator, Position const& pos, GuidUnorderedSet&& participants, SpellInfo const* spellInfo = nullptr);
+ bool Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry, Map* map, Unit* creator, Position const& pos, GuidUnorderedSet&& participants, SpellInfo const* spellInfo = nullptr);
+ void AddActor(ObjectGuid const& actorGuid, uint16 actorIdx);
+ void AddParticipant(ObjectGuid const& participantGuid);
+
+ ObjectGuid const& GetCreatorGuid() const { return _creatorGuid; }
+
+ float GetStationaryX() const override { return _stationaryPosition.GetPositionX(); }
+ float GetStationaryY() const override { return _stationaryPosition.GetPositionY(); }
+ float GetStationaryZ() const override { return _stationaryPosition.GetPositionZ(); }
+ float GetStationaryO() const override { return _stationaryPosition.GetOrientation(); }
+ void RelocateStationaryPosition(Position const& pos) { _stationaryPosition.Relocate(pos); }
+
+ private:
+ Position _stationaryPosition;
+ ObjectGuid _creatorGuid;
+ uint32 _duration;
+ GuidUnorderedSet _participants;
+};
+
+#endif // TRINITYCORE_CONVERSATION_H
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index b1dc8e894bf..333a6a3c5d0 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -182,6 +182,7 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
case HighGuid::Corpse:
case HighGuid::DynamicObject:
case HighGuid::AreaTrigger:
+ case HighGuid::Conversation:
updateType = UPDATETYPE_CREATE_OBJECT2;
break;
case HighGuid::Creature:
@@ -1012,6 +1013,9 @@ uint32 Object::GetDynamicUpdateFieldData(Player const* target, uint32*& flags) c
break;
case TYPEID_CONVERSATION:
flags = ConversationDynamicUpdateFieldFlags;
+
+ if (ToConversation()->GetCreatorGuid() == target->GetGUID())
+ visibleFlag |= UF_FLAG_0x100;
break;
default:
flags = nullptr;
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index f3b4041db3c..5232e9912b2 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -315,6 +315,9 @@ class TC_GAME_API Object
AreaTrigger* ToAreaTrigger() { if (GetTypeId() == TYPEID_AREATRIGGER) return reinterpret_cast<AreaTrigger*>(this); else return NULL; }
AreaTrigger const* ToAreaTrigger() const { if (GetTypeId() == TYPEID_AREATRIGGER) return reinterpret_cast<AreaTrigger const*>(this); else return NULL; }
+ Conversation* ToConversation() { if (GetTypeId() == TYPEID_CONVERSATION) return reinterpret_cast<Conversation*>(this); else return NULL; }
+ Conversation const* ToConversation() const { if (GetTypeId() == TYPEID_CONVERSATION) return reinterpret_cast<Conversation const*>(this); else return NULL; }
+
protected:
Object();
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 41af8b74013..1b41469c373 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -23195,6 +23195,7 @@ template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data
template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, std::set<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, std::set<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(AreaTrigger* target, UpdateData& data, std::set<Unit*>& visibleNow);
+template void Player::UpdateVisibilityOf(Conversation* target, UpdateData& data, std::set<Unit*>& visibleNow);
void Player::UpdateObjectVisibility(bool forced)
{
diff --git a/src/server/game/Globals/ConversationDataStore.cpp b/src/server/game/Globals/ConversationDataStore.cpp
new file mode 100644
index 00000000000..f977a77c845
--- /dev/null
+++ b/src/server/game/Globals/ConversationDataStore.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 "ConversationDataStore.h"
+#include "Containers.h"
+#include "DatabaseEnv.h"
+#include "DB2Stores.h"
+#include "Log.h"
+#include "Timer.h"
+
+namespace
+{
+ std::unordered_map<uint32, ConversationTemplate> _conversationTemplateStore;
+ std::unordered_map<uint32, ConversationActorTemplate> _conversationActorTemplateStore;
+ std::unordered_map<uint32, ConversationLineTemplate> _conversationLineTemplateStore;
+}
+
+void ConversationDataStore::LoadConversationTemplates()
+{
+ _conversationActorTemplateStore.clear();
+ _conversationLineTemplateStore.clear();
+ _conversationTemplateStore.clear();
+
+ std::unordered_map<uint32, std::vector<ConversationActorTemplate const*>> actorsByConversation;
+
+ if (QueryResult actorTemplates = WorldDatabase.Query("SELECT Id, CreatureId, CreatureModelId FROM conversation_actor_template"))
+ {
+ uint32 oldMSTime = getMSTime();
+
+ do
+ {
+ Field* fields = actorTemplates->Fetch();
+
+ uint32 id = fields[0].GetUInt32();
+ ConversationActorTemplate& conversationActor = _conversationActorTemplateStore[id];
+ conversationActor.Id = id;
+ conversationActor.CreatureId = fields[1].GetUInt32();
+ conversationActor.CreatureModelId = fields[2].GetUInt32();
+ }
+ while (actorTemplates->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Conversation actor templates in %u ms", _conversationActorTemplateStore.size(), GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 Conversation actor templates. DB table `conversation_actor_template` is empty.");
+ }
+
+ if (QueryResult lineTemplates = WorldDatabase.Query("SELECT Id, StartTime, UiCameraID, ActorIdx, Unk FROM conversation_line_template"))
+ {
+ uint32 oldMSTime = getMSTime();
+
+ do
+ {
+ Field* fields = lineTemplates->Fetch();
+
+ uint32 id = fields[0].GetUInt32();
+
+ if (!sConversationLineStore.LookupEntry(id))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `conversation_line_template` has template for non existing ConversationLine (ID: %u), skipped", id);
+ continue;
+ }
+
+ ConversationLineTemplate& conversationLine = _conversationLineTemplateStore[id];
+ conversationLine.Id = id;
+ conversationLine.StartTime = fields[1].GetUInt32();
+ conversationLine.UiCameraID = fields[2].GetUInt32();
+ conversationLine.ActorIdx = fields[3].GetUInt16();
+ conversationLine.Unk = fields[4].GetUInt16();
+ }
+ while (lineTemplates->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Conversation line templates in %u ms", _conversationLineTemplateStore.size(), GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 Conversation line templates. DB table `conversation_line_template` is empty.");
+ }
+
+ if (QueryResult actors = WorldDatabase.Query("SELECT ConversationId, ConversationActorId, Idx FROM conversation_actors"))
+ {
+ uint32 oldMSTime = getMSTime();
+ uint32 count = 0;
+
+ do
+ {
+ Field* fields = actors->Fetch();
+
+ uint32 conversationId = fields[0].GetUInt32();
+ uint32 actorId = fields[1].GetUInt32();
+ uint16 idx = fields[2].GetUInt16();
+
+ if (ConversationActorTemplate const* conversationActorTemplate = Trinity::Containers::MapGetValuePtr(_conversationActorTemplateStore, actorId))
+ {
+ std::vector<ConversationActorTemplate const*>& actors = actorsByConversation[conversationId];
+ if (actors.size() <= idx)
+ actors.resize(idx + 1);
+ actors[idx] = conversationActorTemplate;
+ ++count;
+ }
+ else
+ TC_LOG_ERROR("sql.sql", "Table `conversation_actors` references an invalid actor (ID: %u) for Conversation %u, skipped", actorId, conversationId);
+ }
+ while (actors->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u Conversation actors in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 Conversation actors. DB table `conversation_actors` is empty.");
+ }
+
+ if (QueryResult templates = WorldDatabase.Query("SELECT Id, FirstLineId, LastLineEndTime, VerifiedBuild FROM conversation_template"))
+ {
+ uint32 oldMSTime = getMSTime();
+
+ do
+ {
+ Field* fields = templates->Fetch();
+
+ ConversationTemplate conversationTemplate;
+ conversationTemplate.Id = fields[0].GetUInt32();
+ conversationTemplate.FirstLineId = fields[1].GetUInt32();
+ conversationTemplate.LastLineEndTime = fields[2].GetUInt32();
+
+ conversationTemplate.Actors = std::move(actorsByConversation[conversationTemplate.Id]);
+
+ ConversationLineEntry const* currentConversationLine = sConversationLineStore.LookupEntry(conversationTemplate.FirstLineId);
+ if (!currentConversationLine)
+ TC_LOG_ERROR("sql.sql", "Table `conversation_template` references an invalid line (ID: %u) for Conversation %u, skipped", conversationTemplate.FirstLineId, conversationTemplate.Id);
+
+ while (currentConversationLine != nullptr)
+ {
+ if (ConversationLineTemplate const* conversationLineTemplate = Trinity::Containers::MapGetValuePtr(_conversationLineTemplateStore, currentConversationLine->ID))
+ conversationTemplate.Lines.push_back(conversationLineTemplate);
+ else
+ TC_LOG_ERROR("sql.sql", "Table `conversation_line_template` has missing template for line (ID: %u) in Conversation %u, skipped", currentConversationLine->ID, conversationTemplate.Id);
+
+ if (!currentConversationLine->NextLineID)
+ break;
+
+ currentConversationLine = sConversationLineStore.AssertEntry(currentConversationLine->NextLineID);
+ }
+
+ _conversationTemplateStore[conversationTemplate.Id] = conversationTemplate;
+ }
+ while (templates->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Conversation templates in %u ms", _conversationTemplateStore.size(), GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 Conversation templates. DB table `conversation_template` is empty.");
+ }
+}
+
+ConversationTemplate const* ConversationDataStore::GetConversationTemplate(uint32 conversationId) const
+{
+ return Trinity::Containers::MapGetValuePtr(_conversationTemplateStore, conversationId);
+}
+
+ConversationDataStore* ConversationDataStore::Instance()
+{
+ static ConversationDataStore instance;
+ return &instance;
+}
diff --git a/src/server/game/Globals/ConversationDataStore.h b/src/server/game/Globals/ConversationDataStore.h
new file mode 100644
index 00000000000..546de60a2a8
--- /dev/null
+++ b/src/server/game/Globals/ConversationDataStore.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 ConversationDataStore_h__
+#define ConversationDataStore_h__
+
+#include "Define.h"
+
+#include <vector>
+
+struct ConversationActorTemplate
+{
+ uint32 Id;
+ uint32 CreatureId;
+ uint32 CreatureModelId;
+};
+
+#pragma pack(push, 1)
+struct ConversationLineTemplate
+{
+ uint32 Id; // Link to ConversationLine.db2
+ uint32 StartTime; // Time in ms after conversation creation the line is displayed
+ uint32 UiCameraID; // Link to UiCamera.db2
+ uint16 ActorIdx; // Index from conversation_actors
+ uint16 Unk;
+};
+#pragma pack(pop)
+
+struct ConversationTemplate
+{
+ uint32 Id;
+ uint32 FirstLineId; // Link to ConversationLine.db2
+ uint32 LastLineEndTime; // Time in ms after conversation creation the last line fades out
+
+ std::vector<ConversationActorTemplate const*> Actors;
+ std::vector<ConversationLineTemplate const*> Lines;
+};
+
+class TC_GAME_API ConversationDataStore
+{
+public:
+ void LoadConversationTemplates();
+
+ ConversationTemplate const* GetConversationTemplate(uint32 conversationId) const;
+
+ static ConversationDataStore* Instance();
+};
+
+#define sConversationDataStore ConversationDataStore::Instance()
+
+#endif // ConversationDataStore_h__
diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp
index 564b02adc67..acc05ad7f3b 100644
--- a/src/server/game/Globals/ObjectAccessor.cpp
+++ b/src/server/game/Globals/ObjectAccessor.cpp
@@ -119,6 +119,7 @@ WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, ObjectGuid con
case HighGuid::DynamicObject: return GetDynamicObject(p, guid);
case HighGuid::AreaTrigger: return GetAreaTrigger(p, guid);
case HighGuid::Corpse: return GetCorpse(p, guid);
+ case HighGuid::Conversation: return GetConversation(p, guid);
default: return nullptr;
}
}
@@ -156,6 +157,9 @@ Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const& p, ObjectGuid con
case HighGuid::AreaTrigger:
if (typemask & TYPEMASK_AREATRIGGER)
return GetAreaTrigger(p, guid);
+ case HighGuid::Conversation:
+ if (typemask & TYPEMASK_CONVERSATION)
+ return GetConversation(p, guid);
case HighGuid::Corpse:
break;
default:
@@ -195,6 +199,11 @@ AreaTrigger* ObjectAccessor::GetAreaTrigger(WorldObject const& u, ObjectGuid con
return u.GetMap()->GetAreaTrigger(guid);
}
+Conversation* ObjectAccessor::GetConversation(WorldObject const& u, ObjectGuid const& guid)
+{
+ return u.GetMap()->GetConversation(guid);
+}
+
Unit* ObjectAccessor::GetUnit(WorldObject const& u, ObjectGuid const& guid)
{
if (guid.IsPlayer())
diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h
index 08bf2bc3b58..6322c439a43 100644
--- a/src/server/game/Globals/ObjectAccessor.h
+++ b/src/server/game/Globals/ObjectAccessor.h
@@ -71,6 +71,7 @@ namespace ObjectAccessor
TC_GAME_API Transport* GetTransport(ObjectGuid const& guid);
TC_GAME_API DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API AreaTrigger* GetAreaTrigger(WorldObject const& u, ObjectGuid const& guid);
+ TC_GAME_API Conversation* GetConversation(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API Unit* GetUnit(WorldObject const&, ObjectGuid const& guid);
TC_GAME_API Creature* GetCreature(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API Pet* GetPet(WorldObject const&, ObjectGuid const& guid);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index da458834b51..3c245e02a34 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -9758,7 +9758,7 @@ void ObjectMgr::LoadSceneTemplates()
Field* fields = templates->Fetch();
uint32 sceneId = fields[0].GetUInt32();
- SceneTemplate& sceneTemplate = _sceneTemplateStore[sceneId];
+ SceneTemplate& sceneTemplate = _sceneTemplateStore[sceneId];
sceneTemplate.SceneId = sceneId;
sceneTemplate.PlaybackFlags = fields[1].GetUInt32();
sceneTemplate.ScenePackageId = fields[2].GetUInt32();
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 8bd95bf5e82..17231f628a2 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -24,6 +24,7 @@
#include "Bag.h"
#include "Creature.h"
#include "DynamicObject.h"
+#include "Conversation.h"
#include "GameObject.h"
#include "TemporarySummon.h"
#include "Corpse.h"
diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h
index 4c89e90b66e..55e6ae1ab24 100644
--- a/src/server/game/Grids/GridDefines.h
+++ b/src/server/game/Grids/GridDefines.h
@@ -31,6 +31,7 @@ class GameObject;
class Pet;
class Player;
class AreaTrigger;
+class Conversation;
#define MAX_NUMBER_OF_CELLS 8
@@ -58,8 +59,8 @@ class AreaTrigger;
// Creature used instead pet to simplify *::Visit templates (not required duplicate code for Creature->Pet case)
typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, DynamicObject/*farsight target*/) AllWorldObjectTypes;
-typedef TYPELIST_5(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/, AreaTrigger) AllGridObjectTypes;
-typedef TYPELIST_6(Creature, GameObject, DynamicObject, Pet, Corpse, AreaTrigger) AllMapStoredObjectTypes;
+typedef TYPELIST_6(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/, AreaTrigger, Conversation) AllGridObjectTypes;
+typedef TYPELIST_7(Creature, GameObject, DynamicObject, Pet, Corpse, AreaTrigger, Conversation) AllMapStoredObjectTypes;
typedef GridRefManager<Corpse> CorpseMapType;
typedef GridRefManager<Creature> CreatureMapType;
@@ -67,6 +68,7 @@ typedef GridRefManager<DynamicObject> DynamicObjectMapType;
typedef GridRefManager<GameObject> GameObjectMapType;
typedef GridRefManager<Player> PlayerMapType;
typedef GridRefManager<AreaTrigger> AreaTriggerMapType;
+typedef GridRefManager<Conversation> ConversationMapType;
enum GridMapTypeMask
{
@@ -76,7 +78,8 @@ enum GridMapTypeMask
GRID_MAP_TYPE_MASK_GAMEOBJECT = 0x08,
GRID_MAP_TYPE_MASK_PLAYER = 0x10,
GRID_MAP_TYPE_MASK_AREATRIGGER = 0x20,
- GRID_MAP_TYPE_MASK_ALL = 0x3F
+ GRID_MAP_TYPE_MASK_CONVERSATION = 0x40,
+ GRID_MAP_TYPE_MASK_ALL = 0x7F
};
typedef Grid<Player, AllWorldObjectTypes, AllGridObjectTypes> GridType;
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index ebf94bbbc5c..3892db055ec 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -372,4 +372,4 @@ template void ObjectUpdater::Visit<Creature>(CreatureMapType&);
template void ObjectUpdater::Visit<GameObject>(GameObjectMapType&);
template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType&);
template void ObjectUpdater::Visit<AreaTrigger>(AreaTriggerMapType &);
-
+template void ObjectUpdater::Visit<Conversation>(ConversationMapType &);
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index ce1e81468ab..35bf4942af2 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -26,6 +26,7 @@
#include "Corpse.h"
#include "Object.h"
#include "AreaTrigger.h"
+#include "Conversation.h"
#include "DynamicObject.h"
#include "GameObject.h"
#include "Player.h"
@@ -121,6 +122,7 @@ namespace Trinity
void Visit(DynamicObjectMapType &m) { updateObjects<DynamicObject>(m); }
void Visit(CorpseMapType &m) { updateObjects<Corpse>(m); }
void Visit(AreaTriggerMapType &m) { updateObjects<AreaTrigger>(m); }
+ void Visit(ConversationMapType &m) { updateObjects<Conversation>(m); }
};
struct TC_GAME_API MessageDistDeliverer
@@ -189,6 +191,7 @@ namespace Trinity
void Visit(CorpseMapType &m);
void Visit(DynamicObjectMapType &m);
void Visit(AreaTriggerMapType &m);
+ void Visit(ConversationMapType &m);
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) { }
};
@@ -210,6 +213,7 @@ namespace Trinity
void Visit(CorpseMapType &m);
void Visit(DynamicObjectMapType &m);
void Visit(AreaTriggerMapType &m);
+ void Visit(ConversationMapType &m);
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) { }
};
@@ -231,6 +235,7 @@ namespace Trinity
void Visit(GameObjectMapType &m);
void Visit(DynamicObjectMapType &m);
void Visit(AreaTriggerMapType &m);
+ void Visit(ConversationMapType &m);
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) { }
};
@@ -298,6 +303,15 @@ namespace Trinity
i_do(itr->GetSource());
}
+ void Visit(ConversationMapType &m)
+ {
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CONVERSATION))
+ return;
+ for (ConversationMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
+ if (itr->GetSource()->IsInPhase(_searcher))
+ i_do(itr->GetSource());
+ }
+
template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) { }
};
diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
index 0ab703caade..68a1c17bdb3 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
@@ -181,6 +181,29 @@ void Trinity::WorldObjectSearcher<Check>::Visit(AreaTriggerMapType &m)
}
template<class Check>
+void Trinity::WorldObjectSearcher<Check>::Visit(ConversationMapType &m)
+{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CONVERSATION))
+ return;
+
+ // already found
+ if (i_object)
+ return;
+
+ for (ConversationMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
+ {
+ if (!itr->GetSource()->IsInPhase(_searcher))
+ continue;
+
+ if (i_check(itr->GetSource()))
+ {
+ i_object = itr->GetSource();
+ return;
+ }
+ }
+}
+
+template<class Check>
void Trinity::WorldObjectLastSearcher<Check>::Visit(GameObjectMapType &m)
{
if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT))
@@ -277,6 +300,22 @@ void Trinity::WorldObjectLastSearcher<Check>::Visit(AreaTriggerMapType &m)
}
template<class Check>
+void Trinity::WorldObjectLastSearcher<Check>::Visit(ConversationMapType &m)
+{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CONVERSATION))
+ return;
+
+ for (ConversationMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
+ {
+ if (!itr->GetSource()->IsInPhase(_searcher))
+ continue;
+
+ if (i_check(itr->GetSource()))
+ i_object = itr->GetSource();
+ }
+}
+
+template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m)
{
if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER))
@@ -342,6 +381,17 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(AreaTriggerMapType &m)
i_objects.push_back(itr->GetSource());
}
+template<class Check>
+void Trinity::WorldObjectListSearcher<Check>::Visit(ConversationMapType &m)
+{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CONVERSATION))
+ return;
+
+ for (ConversationMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
+ if (i_check(itr->GetSource()))
+ i_objects.push_back(itr->GetSource());
+}
+
// Gameobject searchers
template<class Check>
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index eab7573f552..5534dff3e38 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -24,6 +24,7 @@
#include "DynamicObject.h"
#include "Corpse.h"
#include "AreaTrigger.h"
+#include "Conversation.h"
#include "World.h"
#include "CellImpl.h"
#include "CreatureAI.h"
@@ -238,6 +239,7 @@ void ObjectGridCleaner::Visit(GridRefManager<T> &m)
template void ObjectGridUnloader::Visit(CreatureMapType &);
template void ObjectGridUnloader::Visit(GameObjectMapType &);
template void ObjectGridUnloader::Visit(DynamicObjectMapType &);
+template void ObjectGridUnloader::Visit(ConversationMapType &);
template void ObjectGridUnloader::Visit(AreaTriggerMapType &);
template void ObjectGridCleaner::Visit(CreatureMapType &);
@@ -245,3 +247,4 @@ template void ObjectGridCleaner::Visit<GameObject>(GameObjectMapType &);
template void ObjectGridCleaner::Visit<DynamicObject>(DynamicObjectMapType &);
template void ObjectGridCleaner::Visit<Corpse>(CorpseMapType &);
template void ObjectGridCleaner::Visit<AreaTrigger>(AreaTriggerMapType &);
+template void ObjectGridCleaner::Visit<Conversation>(ConversationMapType &);
diff --git a/src/server/game/Grids/ObjectGridLoader.h b/src/server/game/Grids/ObjectGridLoader.h
index c83a6e7a2d1..71f81f96bf3 100644
--- a/src/server/game/Grids/ObjectGridLoader.h
+++ b/src/server/game/Grids/ObjectGridLoader.h
@@ -41,6 +41,7 @@ class TC_GAME_API ObjectGridLoader
void Visit(CorpseMapType &) const { }
void Visit(DynamicObjectMapType&) const { }
void Visit(AreaTriggerMapType &) const { }
+ void Visit(ConversationMapType &) const { }
void LoadN(void);
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index ac2330e6f1e..9faf6961f45 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -21,6 +21,7 @@
#include "Battleground.h"
#include "MMapFactory.h"
#include "CellImpl.h"
+#include "Conversation.h"
#include "DisableMgr.h"
#include "DynamicTree.h"
#include "GridNotifiers.h"
@@ -3037,6 +3038,9 @@ void Map::RemoveAllObjectsInRemoveList()
case TYPEID_AREATRIGGER:
RemoveFromMap((AreaTrigger*)obj, true);
break;
+ case TYPEID_CONVERSATION:
+ RemoveFromMap((Conversation*)obj, true);
+ break;
case TYPEID_GAMEOBJECT:
{
GameObject* go = obj->ToGameObject();
@@ -3185,12 +3189,14 @@ template TC_GAME_API bool Map::AddToMap(Creature*);
template TC_GAME_API bool Map::AddToMap(GameObject*);
template TC_GAME_API bool Map::AddToMap(DynamicObject*);
template TC_GAME_API bool Map::AddToMap(AreaTrigger*);
+template TC_GAME_API bool Map::AddToMap(Conversation*);
template TC_GAME_API void Map::RemoveFromMap(Corpse*, bool);
template TC_GAME_API void Map::RemoveFromMap(Creature*, bool);
template TC_GAME_API void Map::RemoveFromMap(GameObject*, bool);
template TC_GAME_API void Map::RemoveFromMap(DynamicObject*, bool);
template TC_GAME_API void Map::RemoveFromMap(AreaTrigger*, bool);
+template TC_GAME_API void Map::RemoveFromMap(Conversation*, bool);
/* ******* Dungeon Instance Maps ******* */
@@ -3773,6 +3779,11 @@ AreaTrigger* Map::GetAreaTrigger(ObjectGuid const& guid)
return _objectsStore.Find<AreaTrigger>(guid);
}
+Conversation* Map::GetConversation(ObjectGuid const& guid)
+{
+ return _objectsStore.Find<Conversation>(guid);
+}
+
Corpse* Map::GetCorpse(ObjectGuid const& guid)
{
return _objectsStore.Find<Corpse>(guid);
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 263d65788e8..0e614a89454 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -452,6 +452,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
TempSummon* SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties = NULL, uint32 duration = 0, Unit* summoner = NULL, uint32 spellId = 0, uint32 vehId = 0);
void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = NULL);
AreaTrigger* GetAreaTrigger(ObjectGuid const& guid);
+ Conversation* GetConversation(ObjectGuid const& guid);
Corpse* GetCorpse(ObjectGuid const& guid);
Creature* GetCreature(ObjectGuid const& guid);
DynamicObject* GetDynamicObject(ObjectGuid const& guid);
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 98e3dd04450..f29f71b43f2 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -1241,7 +1241,7 @@ enum SpellEffectName
SPELL_EFFECT_CREATE_SHIPMENT = 216,
SPELL_EFFECT_UPGRADE_GARRISON = 217,
SPELL_EFFECT_218 = 218,
- SPELL_EFFECT_219 = 219,
+ SPELL_EFFECT_CREATE_CONVERSATION = 219,
SPELL_EFFECT_ADD_GARRISON_FOLLOWER = 220,
SPELL_EFFECT_221 = 221,
SPELL_EFFECT_CREATE_HEIRLOOM_ITEM = 222,
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 80dbbf81bfe..39a5b705563 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -444,6 +444,7 @@ class TC_GAME_API Spell
void EffectDestroyItem(SpellEffIndex effIndex);
void EffectLearnGarrisonBuilding(SpellEffIndex effIndex);
void EffectCreateGarrison(SpellEffIndex effIndex);
+ void EffectCreateConversation(SpellEffIndex effIndex);
void EffectAddGarrisonFollower(SpellEffIndex effIndex);
void EffectActivateGarrisonBuilding(SpellEffIndex effIndex);
void EffectHealBattlePetPct(SpellEffIndex effIndex);
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index e4e309ecf30..a1eb05d1da9 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -62,6 +62,7 @@
#include "MiscPackets.h"
#include "SpellPackets.h"
#include "TalentPackets.h"
+#include "Conversation.h"
pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
{
@@ -284,7 +285,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectNULL, //216 SPELL_EFFECT_CREATE_SHIPMENT
&Spell::EffectNULL, //217 SPELL_EFFECT_UPGRADE_GARRISON
&Spell::EffectNULL, //218 SPELL_EFFECT_218
- &Spell::EffectNULL, //219 SPELL_EFFECT_219
+ &Spell::EffectCreateConversation, //219 SPELL_EFFECT_CREATE_CONVERSATION
&Spell::EffectAddGarrisonFollower, //220 SPELL_EFFECT_ADD_GARRISON_FOLLOWER
&Spell::EffectNULL, //221 SPELL_EFFECT_221
&Spell::EffectCreateHeirloomItem, //222 SPELL_EFFECT_CREATE_HEIRLOOM_ITEM
@@ -5659,6 +5660,17 @@ void Spell::EffectCreateGarrison(SpellEffIndex effIndex)
unitTarget->ToPlayer()->CreateGarrison(GetEffect(effIndex)->MiscValue);
}
+void Spell::EffectCreateConversation(SpellEffIndex /*effIndex*/)
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
+ return;
+
+ if (!m_targets.HasDst())
+ return;
+
+ Conversation::CreateConversation(effectInfo->MiscValue, GetCaster(), destTarget->GetPosition(), { GetCaster()->GetGUID() }, GetSpellInfo());
+}
+
void Spell::EffectAddGarrisonFollower(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 826cf0fece3..bef98d77775 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -938,7 +938,7 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] =
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 216 SPELL_EFFECT_CREATE_SHIPMENT
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 217 SPELL_EFFECT_UPGRADE_GARRISON
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 218 SPELL_EFFECT_218
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 219 SPELL_EFFECT_219
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 219 SPELL_EFFECT_CREATE_CONVERSATION
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 220 SPELL_EFFECT_ADD_GARRISON_FOLLOWER
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 221 SPELL_EFFECT_221
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 222 SPELL_EFFECT_CREATE_HEIRLOOM_ITEM
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 5ced6e8bfab..02d6704ee4f 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -37,6 +37,7 @@
#include "CharacterTemplateDataStore.h"
#include "Chat.h"
#include "Config.h"
+#include "ConversationDataStore.h"
#include "CreatureAIRegistry.h"
#include "CreatureGroups.h"
#include "CreatureTextMgr.h"
@@ -1835,6 +1836,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading AreaTrigger Templates...");
sAreaTriggerDataStore->LoadAreaTriggerTemplates();
+ TC_LOG_INFO("server.loading", "Loading Conversation Templates...");
+ sConversationDataStore->LoadConversationTemplates();
+
TC_LOG_INFO("server.loading", "Loading Scenes Templates...");
sObjectMgr->LoadSceneTemplates();
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp
index 1419a5b3b74..bfa60398261 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -29,6 +29,7 @@ EndScriptData */
#include "Chat.h"
#include "Cell.h"
#include "CellImpl.h"
+#include "Conversation.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "GossipDef.h"
@@ -102,6 +103,7 @@ public:
{ "boundary", rbac::RBAC_PERM_COMMAND_DEBUG_BOUNDARY, false, &HandleDebugBoundaryCommand, "" },
{ "raidreset", rbac::RBAC_PERM_COMMAND_INSTANCE_UNBIND, false, &HandleDebugRaidResetCommand, "" },
{ "neargraveyard", rbac::RBAC_PERM_COMMAND_NEARGRAVEYARD, false, &HandleDebugNearGraveyard, "" },
+ { "conversation" , rbac::RBAC_PERM_COMMAND_DEBUG_CONVERSATION, false, &HandleDebugConversationCommand, "" },
};
static std::vector<ChatCommand> commandTable =
{
@@ -1567,6 +1569,29 @@ public:
return true;
}
+
+ static bool HandleDebugConversationCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ char const* conversationEntryStr = strtok((char*)args, " ");
+
+ if (!conversationEntryStr)
+ return false;
+
+ uint32 conversationEntry = atoi(conversationEntryStr);
+ Player* target = handler->getSelectedPlayerOrSelf();
+
+ if (!target)
+ {
+ handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ return Conversation::CreateConversation(conversationEntry, target, *target, { target->GetGUID() }) != nullptr;
+ }
};
void AddSC_debug_commandscript()
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index 1b54aa4f03e..2732d6d8be7 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -29,6 +29,7 @@ EndScriptData */
#include "BattlegroundMgr.h"
#include "CharacterTemplateDataStore.h"
#include "Chat.h"
+#include "ConversationDataStore.h"
#include "CreatureTextMgr.h"
#include "DisableMgr.h"
#include "Language.h"
@@ -81,6 +82,7 @@ public:
{ "command", rbac::RBAC_PERM_COMMAND_RELOAD_COMMAND, true, &HandleReloadCommandCommand, "" },
{ "conditions", rbac::RBAC_PERM_COMMAND_RELOAD_CONDITIONS, true, &HandleReloadConditions, "" },
{ "config", rbac::RBAC_PERM_COMMAND_RELOAD_CONFIG, true, &HandleReloadConfigCommand, "" },
+ { "conversation_template", rbac::RBAC_PERM_COMMAND_RELOAD_CONVERSATION_TEMPLATE, true, &HandleReloadConversationTemplateCommand, "" },
{ "creature_text", rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_TEXT, true, &HandleReloadCreatureText, "" },
{ "creature_questender", rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_QUESTENDER, true, &HandleReloadCreatureQuestEnderCommand, "" },
{ "creature_linked_respawn", rbac::RBAC_PERM_COMMAND_RELOAD_CREATURE_LINKED_RESPAWN, true, &HandleReloadLinkedRespawnCommand, "" },
@@ -1150,6 +1152,14 @@ public:
return true;
}
+ static bool HandleReloadConversationTemplateCommand(ChatHandler* handler, const char* /*args*/)
+ {
+ TC_LOG_INFO("misc", "Reloading conversation_* tables...");
+ sConversationDataStore->LoadConversationTemplates();
+ handler->SendGlobalGMSysMessage("Conversation templates reloaded.");
+ return true;
+ }
+
static bool HandleReloadRBACCommand(ChatHandler* handler, const char* /*args*/)
{
TC_LOG_INFO("misc", "Reloading RBAC tables...");
diff --git a/src/server/shared/Dynamic/TypeList.h b/src/server/shared/Dynamic/TypeList.h
index a8dcea05bcc..9bc455587c8 100644
--- a/src/server/shared/Dynamic/TypeList.h
+++ b/src/server/shared/Dynamic/TypeList.h
@@ -35,11 +35,12 @@ struct TypeList
};
// enough for now.. can be expand at any point in time as needed
-#define TYPELIST_1(T1) TypeList<T1, TypeNull>
-#define TYPELIST_2(T1, T2) TypeList<T1, TYPELIST_1(T2) >
-#define TYPELIST_3(T1, T2, T3) TypeList<T1, TYPELIST_2(T2, T3) >
-#define TYPELIST_4(T1, T2, T3, T4) TypeList<T1, TYPELIST_3(T2, T3, T4) >
-#define TYPELIST_5(T1, T2, T3, T4, T5) TypeList<T1, TYPELIST_4(T2, T3, T4, T5) >
-#define TYPELIST_6(T1, T2, T3, T4, T5, T6) TypeList<T1, TYPELIST_5(T2, T3, T4, T5, T6) >
+#define TYPELIST_1(T1) TypeList<T1, TypeNull>
+#define TYPELIST_2(T1, T2) TypeList<T1, TYPELIST_1(T2) >
+#define TYPELIST_3(T1, T2, T3) TypeList<T1, TYPELIST_2(T2, T3) >
+#define TYPELIST_4(T1, T2, T3, T4) TypeList<T1, TYPELIST_3(T2, T3, T4) >
+#define TYPELIST_5(T1, T2, T3, T4, T5) TypeList<T1, TYPELIST_4(T2, T3, T4, T5) >
+#define TYPELIST_6(T1, T2, T3, T4, T5, T6) TypeList<T1, TYPELIST_5(T2, T3, T4, T5, T6) >
+#define TYPELIST_7(T1, T2, T3, T4, T5, T6, T7) TypeList<T1, TYPELIST_6(T2, T3, T4, T5, T6, T7) >
#endif