1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#ifndef TRINITY_CREATURE_TEXT_MGR_H
#define TRINITY_CREATURE_TEXT_MGR_H
#include "Creature.h"
#include "GridNotifiers.h"
#include "ObjectAccessor.h"
#include "SharedDefines.h"
#include "Opcodes.h"
enum CreatureTextRange
{
TEXT_RANGE_NORMAL = 0,
TEXT_RANGE_AREA = 1,
TEXT_RANGE_ZONE = 2,
TEXT_RANGE_MAP = 3,
TEXT_RANGE_WORLD = 4
};
struct CreatureTextEntry
{
uint32 entry;
uint8 group;
uint8 id;
std::string text;
ChatMsg type;
Language lang;
float probability;
Emote emote;
uint32 duration;
uint32 sound;
CreatureTextRange TextRange;
};
struct CreatureTextLocale
{
StringVector Text;
};
struct CreatureTextId
{
CreatureTextId(uint32 e, uint32 g, uint32 i) : entry(e), textGroup(g), textId(i)
{
}
bool operator<(CreatureTextId const& right) const
{
return memcmp(this, &right, sizeof(CreatureTextId)) < 0;
}
uint32 entry;
uint32 textGroup;
uint32 textId;
};
typedef std::vector<CreatureTextEntry> CreatureTextGroup; // texts in a group
typedef UNORDERED_MAP<uint8, CreatureTextGroup> CreatureTextHolder; // groups for a creature by groupid
typedef UNORDERED_MAP<uint32, CreatureTextHolder> CreatureTextMap; // all creatures by entry
typedef std::map<CreatureTextId, CreatureTextLocale> LocaleCreatureTextMap;
//used for handling non-repeatable random texts
typedef std::vector<uint8> CreatureTextRepeatIds;
typedef UNORDERED_MAP<uint8, CreatureTextRepeatIds> CreatureTextRepeatGroup;
typedef UNORDERED_MAP<uint64, CreatureTextRepeatGroup> CreatureTextRepeatMap;//guid based
class CreatureTextMgr
{
friend class ACE_Singleton<CreatureTextMgr, ACE_Null_Mutex>;
CreatureTextMgr() { }
public:
~CreatureTextMgr() { }
void LoadCreatureTexts();
void LoadCreatureTextLocales();
CreatureTextMap const& GetTextMap() const { return mTextMap; }
void SendSound(Creature* source, uint32 sound, ChatMsg msgType, WorldObject const* whisperTarget, CreatureTextRange range, TeamId teamId, bool gmOnly);
void SendEmote(Unit* source, uint32 emote);
//if sent, returns the 'duration' of the text else 0 if error
uint32 SendChat(Creature* source, uint8 textGroup, WorldObject const* whisperTarget = NULL, ChatMsg msgType = CHAT_MSG_ADDON, Language language = LANG_ADDON, CreatureTextRange range = TEXT_RANGE_NORMAL, uint32 sound = 0, TeamId teamId = TEAM_NEUTRAL, bool gmOnly = false, Player* srcPlr = NULL);
bool TextExist(uint32 sourceEntry, uint8 textGroup);
std::string GetLocalizedChatString(uint32 entry, uint8 textGroup, uint32 id, LocaleConstant locale) const;
template<class Builder> void SendChatPacket(WorldObject* source, Builder const& builder, ChatMsg msgType, WorldObject const* whisperTarget = NULL, CreatureTextRange range = TEXT_RANGE_NORMAL, TeamId teamId = TEAM_NEUTRAL, bool gmOnly = false) const;
private:
CreatureTextRepeatIds GetRepeatGroup(Creature* source, uint8 textGroup);
void SetRepeatId(Creature* source, uint8 textGroup, uint8 id);
void SendNonChatPacket(WorldObject* source, WorldPacket* data, ChatMsg msgType, WorldObject const* whisperTarget, CreatureTextRange range, TeamId teamId, bool gmOnly) const;
float GetRangeForChatType(ChatMsg msgType) const;
CreatureTextMap mTextMap;
CreatureTextRepeatMap mTextRepeatMap;
LocaleCreatureTextMap mLocaleTextMap;
};
#define sCreatureTextMgr ACE_Singleton<CreatureTextMgr, ACE_Null_Mutex>::instance()
template<class Builder>
class CreatureTextLocalizer
{
public:
CreatureTextLocalizer(Builder const& builder, ChatMsg msgType) : _builder(builder), _msgType(msgType)
{
_packetCache.resize(TOTAL_LOCALES, NULL);
}
~CreatureTextLocalizer()
{
for (size_t i = 0; i < _packetCache.size(); ++i)
{
if (_packetCache[i])
delete _packetCache[i]->first;
delete _packetCache[i];
}
}
void operator()(Player* player)
{
LocaleConstant loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
WorldPacket* messageTemplate;
size_t whisperGUIDpos;
// create if not cached yet
if (!_packetCache[loc_idx])
{
messageTemplate = new WorldPacket();
whisperGUIDpos = _builder(messageTemplate, loc_idx);
ASSERT(messageTemplate->GetOpcode() != MSG_NULL_ACTION);
_packetCache[loc_idx] = new std::pair<WorldPacket*, size_t>(messageTemplate, whisperGUIDpos);
}
else
{
messageTemplate = _packetCache[loc_idx]->first;
whisperGUIDpos = _packetCache[loc_idx]->second;
}
WorldPacket data(*messageTemplate);
switch (_msgType)
{
case CHAT_MSG_MONSTER_WHISPER:
case CHAT_MSG_RAID_BOSS_WHISPER:
data.put<uint64>(whisperGUIDpos, player->GetGUID());
break;
default:
break;
}
player->SendDirectMessage(&data);
}
private:
std::vector<std::pair<WorldPacket*, size_t>* > _packetCache;
Builder const& _builder;
ChatMsg _msgType;
};
template<class Builder>
void CreatureTextMgr::SendChatPacket(WorldObject* source, Builder const& builder, ChatMsg msgType, WorldObject const* whisperTarget /*= NULL*/, CreatureTextRange range /*= TEXT_RANGE_NORMAL*/, TeamId teamId /*= TEAM_NEUTRAL*/, bool gmOnly /*= false*/) const
{
if (!source)
return;
CreatureTextLocalizer<Builder> localizer(builder, msgType);
switch (msgType)
{
case CHAT_MSG_MONSTER_WHISPER:
case CHAT_MSG_RAID_BOSS_WHISPER:
{
if (range == TEXT_RANGE_NORMAL) //ignores team and gmOnly
{
if (!whisperTarget || whisperTarget->GetTypeId() != TYPEID_PLAYER)
return;
localizer(const_cast<Player*>(whisperTarget->ToPlayer()));
return;
}
break;
}
default:
break;
}
switch (range)
{
case TEXT_RANGE_AREA:
{
uint32 areaId = source->GetAreaId();
Map::PlayerList const& players = source->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (itr->GetSource()->GetAreaId() == areaId && (teamId == TEAM_NEUTRAL || itr->GetSource()->GetTeamId() == teamId) && (!gmOnly || itr->GetSource()->IsGameMaster()))
localizer(itr->GetSource());
return;
}
case TEXT_RANGE_ZONE:
{
uint32 zoneId = source->GetZoneId();
Map::PlayerList const& players = source->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (itr->GetSource()->GetZoneId() == zoneId && (teamId == TEAM_NEUTRAL || itr->GetSource()->GetTeamId() == teamId) && (!gmOnly || itr->GetSource()->IsGameMaster()))
localizer(itr->GetSource());
return;
}
case TEXT_RANGE_MAP:
{
Map::PlayerList const& players = source->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if ((teamId == TEAM_NEUTRAL || itr->GetSource()->GetTeamId() == teamId) && (!gmOnly || itr->GetSource()->IsGameMaster()))
localizer(itr->GetSource());
return;
}
case TEXT_RANGE_WORLD:
{
SessionMap const& smap = sWorld->GetAllSessions();
for (SessionMap::const_iterator itr = smap.begin(); itr != smap.end(); ++itr)
if (Player* player = itr->second->GetPlayer())
if ((teamId == TEAM_NEUTRAL || player->GetTeamId() == teamId) && (!gmOnly || player->IsGameMaster()))
localizer(player);
return;
}
case TEXT_RANGE_NORMAL:
default:
break;
}
float dist = GetRangeForChatType(msgType);
// xinef: hack for boss emote
if (msgType == CHAT_MSG_RAID_BOSS_EMOTE && source->GetMap()->IsDungeon())
dist = 250.0f;
Trinity::PlayerDistWorker<CreatureTextLocalizer<Builder> > worker(source, dist, localizer);
source->VisitNearbyWorldObject(dist, worker);
}
#endif
|