TrinityCore
Loading...
Searching...
No Matches
CreatureTextMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "CreatureTextMgr.h"
19#include "CreatureTextMgrImpl.h"
20#include "CellImpl.h"
21#include "Chat.h"
22#include "Common.h"
23#include "Containers.h"
24#include "DatabaseEnv.h"
25#include "DBCStores.h"
26#include "GridNotifiersImpl.h"
27#include "Log.h"
28#include "MiscPackets.h"
29#include "ObjectMgr.h"
30#include "World.h"
31
33{
34 public:
35 CreatureTextBuilder(WorldObject const* obj, uint8 gender, ChatMsg msgtype, uint8 textGroup, uint32 id, uint32 language, WorldObject const* target)
36 : _source(obj), _gender(gender), _msgType(msgtype), _textGroup(textGroup), _textId(id), _language(language), _target(target) { }
37
38 size_t operator()(WorldPacket* data, LocaleConstant locale) const
39 {
40 std::string const& text = sCreatureTextMgr->GetLocalizedChatString(_source->GetEntry(), _gender, _textGroup, _textId, locale);
41
42 return ChatHandler::BuildChatPacket(*data, _msgType, Language(_language), _source, _target, text, 0, "", locale);
43 }
44
45 private:
53};
54
56{
57 public:
58 PlayerTextBuilder(WorldObject const* obj, WorldObject const* speaker, uint8 gender, ChatMsg msgtype, uint8 textGroup, uint32 id, uint32 language, WorldObject const* target)
59 : _source(obj), _talker(speaker), _gender(gender), _msgType(msgtype), _textGroup(textGroup), _textId(id), _language(language), _target(target) { }
60
61 size_t operator()(WorldPacket* data, LocaleConstant locale) const
62 {
63 std::string const& text = sCreatureTextMgr->GetLocalizedChatString(_source->GetEntry(), _gender, _textGroup, _textId, locale);
64
65 return ChatHandler::BuildChatPacket(*data, _msgType, Language(_language), _talker, _target, text, 0, "", locale);
66 }
67
68 private:
77};
78
84
86{
87 uint32 oldMSTime = getMSTime();
88
89 mTextMap.clear(); // for reload case
90 //all currently used temp texts are NOT reset
91
93 PreparedQueryResult result = WorldDatabase.Query(stmt);
94
95 if (!result)
96 {
97 TC_LOG_INFO("server.loading", ">> Loaded 0 ceature texts. DB table `creature_text` is empty.");
98
99 return;
100 }
101
102 uint32 textCount = 0;
103
104 do
105 {
106 Field* fields = result->Fetch();
108
109 temp.creatureId = fields[0].GetUInt32();
110 temp.groupId = fields[1].GetUInt8();
111 temp.id = fields[2].GetUInt8();
112 temp.text = fields[3].GetString();
113 temp.type = ChatMsg(fields[4].GetUInt8());
114 temp.lang = Language(fields[5].GetUInt8());
115 temp.probability = fields[6].GetFloat();
116 temp.emote = Emote(fields[7].GetUInt32());
117 temp.duration = fields[8].GetUInt32();
118 temp.sound = fields[9].GetUInt32();
119 temp.BroadcastTextId = fields[10].GetUInt32();
120 temp.TextRange = CreatureTextRange(fields[11].GetUInt8());
121
122 if (temp.sound)
123 {
124 if (!sSoundEntriesStore.LookupEntry(temp.sound))
125 {
126 TC_LOG_ERROR("sql.sql", "CreatureTextMgr: Entry {}, Group {} in table `creature_text` has Sound {} but sound does not exist.", temp.creatureId, temp.groupId, temp.sound);
127 temp.sound = 0;
128 }
129 }
130
131 if (!GetLanguageDescByID(temp.lang))
132 {
133 TC_LOG_ERROR("sql.sql", "CreatureTextMgr: Entry {}, Group {} in table `creature_text` using Language {} but Language does not exist.", temp.creatureId, temp.groupId, uint32(temp.lang));
134 temp.lang = LANG_UNIVERSAL;
135 }
136
137 if (temp.type >= MAX_CHAT_MSG_TYPE)
138 {
139 TC_LOG_ERROR("sql.sql", "CreatureTextMgr: Entry {}, Group {} in table `creature_text` has Type {} but this Chat Type does not exist.", temp.creatureId, temp.groupId, uint32(temp.type));
140 temp.type = CHAT_MSG_SAY;
141 }
142
143 if (temp.emote)
144 {
145 if (!sEmotesStore.LookupEntry(temp.emote))
146 {
147 TC_LOG_ERROR("sql.sql", "CreatureTextMgr: Entry {}, Group {} in table `creature_text` has Emote {} but emote does not exist.", temp.creatureId, temp.groupId, uint32(temp.emote));
149 }
150 }
151
152 if (temp.BroadcastTextId)
153 {
154 if (!sObjectMgr->GetBroadcastText(temp.BroadcastTextId))
155 {
156 TC_LOG_ERROR("sql.sql", "CreatureTextMgr: Entry {}, Group {}, Id {} in table `creature_text` has non-existing or incompatible BroadcastTextId {}.", temp.creatureId, temp.groupId, temp.id, temp.BroadcastTextId);
157 temp.BroadcastTextId = 0;
158 }
159 }
160
161 if (temp.TextRange > TEXT_RANGE_WORLD)
162 {
163 TC_LOG_ERROR("sql.sql", "CreatureTextMgr: Entry {}, Group {}, Id {} in table `creature_text` has incorrect TextRange {}.", temp.creatureId, temp.groupId, temp.id, temp.TextRange);
165 }
166
167 // add the text into our entry's group
168 mTextMap[temp.creatureId][temp.groupId].push_back(temp);
169
170 ++textCount;
171 }
172 while (result->NextRow());
173
174 TC_LOG_INFO("server.loading", ">> Loaded {} creature texts for {} creatures in {} ms", textCount, mTextMap.size(), GetMSTimeDiffToNow(oldMSTime));
175}
176
178{
179 uint32 oldMSTime = getMSTime();
180
181 mLocaleTextMap.clear(); // for reload case
182
183 // 0 1 2 3 4
184 QueryResult result = WorldDatabase.Query("SELECT CreatureID, GroupID, ID, Locale, Text FROM creature_text_locale");
185
186 if (!result)
187 return;
188
189 do
190 {
191 Field* fields = result->Fetch();
192
193 uint32 creatureId = fields[0].GetUInt32();
194 uint32 groupId = fields[1].GetUInt8();
195 uint32 id = fields[2].GetUInt8();
196 std::string localeName = fields[3].GetString();
197
198 LocaleConstant locale = GetLocaleByName(localeName);
199 if (locale == LOCALE_enUS)
200 continue;
201
202 CreatureTextLocale& data = mLocaleTextMap[CreatureTextId(creatureId, groupId, id)];
203 ObjectMgr::AddLocaleString(fields[4].GetString(), locale, data.Text);
204 } while (result->NextRow());
205
206 TC_LOG_INFO("server.loading", ">> Loaded {} creature localized texts in {} ms", uint32(mLocaleTextMap.size()), GetMSTimeDiffToNow(oldMSTime));
207}
208
209uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject const* whisperTarget /*= nullptr*/, ChatMsg msgType /*= CHAT_MSG_ADDON*/, Language language /*= LANG_ADDON*/, CreatureTextRange range /*= TEXT_RANGE_NORMAL*/, uint32 sound /*= 0*/, Team team /*= TEAM_OTHER*/, bool gmOnly /*= false*/, Player* srcPlr /*= nullptr*/)
210{
211 if (!source)
212 return 0;
213
214 CreatureTextMap::const_iterator sList = mTextMap.find(source->GetEntry());
215 if (sList == mTextMap.end())
216 {
217 TC_LOG_ERROR("sql.sql.creaturetextmgr", "CreatureTextMgr: Could not find Text for Creature {} ({}) in 'creature_text' table. Ignoring.", source->GetName(), source->GetGUID().ToString());
218 return 0;
219 }
220
221 CreatureTextHolder const& textHolder = sList->second;
222 CreatureTextHolder::const_iterator itr = textHolder.find(textGroup);
223 if (itr == textHolder.end())
224 {
225 TC_LOG_ERROR("sql.sql.creaturetextmgr", "CreatureTextMgr: Could not find TextGroup {} for Creature {} ({}) in 'creature_text' table. Ignoring.", uint32(textGroup), source->GetName(), source->GetGUID().ToString());
226 return 0;
227 }
228
229 CreatureTextGroup const& textGroupContainer = itr->second; //has all texts in the group
230 CreatureTextRepeatIds repeatGroup = source->GetTextRepeatGroup(textGroup);//has all textIDs from the group that were already said
231 CreatureTextGroup tempGroup;//will use this to talk after sorting repeatGroup
232
233 for (CreatureTextGroup::const_iterator giter = textGroupContainer.begin(); giter != textGroupContainer.end(); ++giter)
234 if (std::find(repeatGroup.begin(), repeatGroup.end(), giter->id) == repeatGroup.end())
235 tempGroup.push_back(*giter);
236
237 if (tempGroup.empty())
238 {
239 source->ClearTextRepeatGroup(textGroup);
240 tempGroup = textGroupContainer;
241 }
242
243 auto iter = Trinity::Containers::SelectRandomWeightedContainerElement(tempGroup, [](CreatureTextEntry const& t) -> double
244 {
245 return t.probability;
246 });
247
248 ChatMsg finalType = (msgType == CHAT_MSG_ADDON) ? iter->type : msgType;
249 Language finalLang = (language == LANG_ADDON) ? iter->lang : language;
250 uint32 finalSound = sound ? sound : iter->sound;
251
252 if (range == TEXT_RANGE_NORMAL)
253 range = iter->TextRange;
254
255 if (finalSound)
256 SendSound(source, finalSound, finalType, whisperTarget, range, team, gmOnly);
257
258 Unit* finalSource = source;
259 if (srcPlr)
260 finalSource = srcPlr;
261
262 if (iter->emote)
263 SendEmote(finalSource, iter->emote);
264
265 if (srcPlr)
266 {
267 PlayerTextBuilder builder(source, finalSource, finalSource->GetGender(), finalType, iter->groupId, iter->id, finalLang, whisperTarget);
268 SendChatPacket(finalSource, builder, finalType, whisperTarget, range, team, gmOnly);
269 }
270 else
271 {
272 CreatureTextBuilder builder(finalSource, finalSource->GetGender(), finalType, iter->groupId, iter->id, finalLang, whisperTarget);
273 SendChatPacket(finalSource, builder, finalType, whisperTarget, range, team, gmOnly);
274 }
275
276 source->SetTextRepeatId(textGroup, iter->id);
277 return iter->duration;
278}
279
281{
282 float dist = sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY);
283 switch (msgType)
284 {
286 dist = sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL);
287 break;
290 dist = sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE);
291 break;
292 default:
293 break;
294 }
295
296 return dist;
297}
298
299void CreatureTextMgr::SendSound(Creature* source, uint32 sound, ChatMsg msgType, WorldObject const* whisperTarget, CreatureTextRange range, Team team, bool gmOnly)
300{
301 if (!sound || !source)
302 return;
303
304 SendNonChatPacket(source, WorldPackets::Misc::PlaySound(sound).Write(), msgType, whisperTarget, range, team, gmOnly);
305}
306
307void CreatureTextMgr::SendNonChatPacket(WorldObject* source, WorldPacket const* data, ChatMsg msgType, WorldObject const* whisperTarget, CreatureTextRange range, Team team, bool gmOnly) const
308{
309 switch (msgType)
310 {
312 {
313 if (!whisperTarget)
314 return;
315
316 if (Player const* whisperPlayer = whisperTarget->ToPlayer())
317 {
318 if (Group const* group = whisperPlayer->GetGroup())
319 group->BroadcastWorker([data](Player* player) { player->SendDirectMessage(data); });
320 }
321 return;
322 }
325 {
326 if (range == TEXT_RANGE_NORMAL) // ignores team and gmOnly
327 {
328 if (!whisperTarget || whisperTarget->GetTypeId() != TYPEID_PLAYER)
329 return;
330
331 whisperTarget->ToPlayer()->SendDirectMessage(data);
332 return;
333 }
334 break;
335 }
336 default:
337 break;
338 }
339
340 switch (range)
341 {
342 case TEXT_RANGE_AREA:
343 {
344 uint32 areaId = source->GetAreaId();
345 Map::PlayerList const& players = source->GetMap()->GetPlayers();
346 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
347 if (itr->GetSource()->GetAreaId() == areaId && (!team || Team(itr->GetSource()->GetTeam()) == team) && (!gmOnly || itr->GetSource()->IsGameMaster()))
348 itr->GetSource()->SendDirectMessage(data);
349 return;
350 }
351 case TEXT_RANGE_ZONE:
352 {
353 uint32 zoneId = source->GetZoneId();
354 Map::PlayerList const& players = source->GetMap()->GetPlayers();
355 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
356 if (itr->GetSource()->GetZoneId() == zoneId && (!team || Team(itr->GetSource()->GetTeam()) == team) && (!gmOnly || itr->GetSource()->IsGameMaster()))
357 itr->GetSource()->SendDirectMessage(data);
358 return;
359 }
360 case TEXT_RANGE_MAP:
361 {
362 Map::PlayerList const& players = source->GetMap()->GetPlayers();
363 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
364 if ((!team || Team(itr->GetSource()->GetTeam()) == team) && (!gmOnly || itr->GetSource()->IsGameMaster()))
365 itr->GetSource()->SendDirectMessage(data);
366 return;
367 }
368 case TEXT_RANGE_WORLD:
369 {
370 SessionMap const& smap = sWorld->GetAllSessions();
371 for (SessionMap::const_iterator iter = smap.begin(); iter != smap.end(); ++iter)
372 if (Player* player = iter->second->GetPlayer())
373 if ((!team || Team(player->GetTeam()) == team) && (!gmOnly || player->IsGameMaster()))
374 player->SendDirectMessage(data);
375 return;
376 }
378 default:
379 break;
380 }
381
382 float dist = GetRangeForChatType(msgType);
383 source->SendMessageToSetInRange(data, dist, true);
384}
385
387{
388 if (!source)
389 return;
390
391 source->HandleEmoteCommand(emote);
392}
393
394bool CreatureTextMgr::TextExist(uint32 sourceEntry, uint8 textGroup)
395{
396 if (!sourceEntry)
397 return false;
398
399 CreatureTextMap::const_iterator sList = mTextMap.find(sourceEntry);
400 if (sList == mTextMap.end())
401 {
402 TC_LOG_DEBUG("entities.unit", "CreatureTextMgr::TextExist: Could not find Text for Creature (entry {}) in 'creature_text' table.", sourceEntry);
403 return false;
404 }
405
406 CreatureTextHolder const& textHolder = sList->second;
407 CreatureTextHolder::const_iterator itr = textHolder.find(textGroup);
408 if (itr == textHolder.end())
409 {
410 TC_LOG_DEBUG("entities.unit", "CreatureTextMgr::TextExist: Could not find TextGroup {} for Creature (entry {}).", uint32(textGroup), sourceEntry);
411 return false;
412 }
413
414 return true;
415}
416
417std::string CreatureTextMgr::GetLocalizedChatString(uint32 entry, uint8 gender, uint8 textGroup, uint32 id, LocaleConstant locale) const
418{
419 CreatureTextMap::const_iterator mapitr = mTextMap.find(entry);
420 if (mapitr == mTextMap.end())
421 return "";
422
423 CreatureTextHolder::const_iterator holderItr = mapitr->second.find(textGroup);
424 if (holderItr == mapitr->second.end())
425 return "";
426
427 CreatureTextGroup::const_iterator groupItr = holderItr->second.begin();
428 for (; groupItr != holderItr->second.end(); ++groupItr)
429 if (groupItr->id == id)
430 break;
431
432 if (groupItr == holderItr->second.end())
433 return "";
434
435 if (locale > MAX_LOCALES)
436 locale = DEFAULT_LOCALE;
437
438 std::string baseText = "";
439 BroadcastText const* bct = sObjectMgr->GetBroadcastText(groupItr->BroadcastTextId);
440
441 if (bct)
442 baseText = bct->GetText(locale, gender);
443 else
444 baseText = groupItr->text;
445
446 if (locale != DEFAULT_LOCALE && !bct)
447 {
448 LocaleCreatureTextMap::const_iterator locItr = mLocaleTextMap.find(CreatureTextId(entry, uint32(textGroup), id));
449 if (locItr != mLocaleTextMap.end())
450 ObjectMgr::GetLocaleString(locItr->second.Text, locale, baseText);
451 }
452
453 return baseText;
454}
LocaleConstant GetLocaleByName(const std::string &name)
Definition Common.cpp:33
LocaleConstant
Definition Common.h:48
@ LOCALE_enUS
Definition Common.h:49
#define DEFAULT_LOCALE
Definition Common.h:62
#define MAX_LOCALES
Definition Common.h:64
#define sCreatureTextMgr
std::vector< CreatureTextEntry > CreatureTextGroup
std::unordered_map< uint8, CreatureTextGroup > CreatureTextHolder
CreatureTextRange
@ TEXT_RANGE_ZONE
@ TEXT_RANGE_AREA
@ TEXT_RANGE_WORLD
@ TEXT_RANGE_NORMAL
@ TEXT_RANGE_MAP
std::vector< uint8 > CreatureTextRepeatIds
Definition Creature.h:58
DBCStorage< SoundEntriesEntry > sSoundEntriesStore(SoundEntriesfmt)
DBCStorage< EmotesEntry > sEmotesStore(EmotesEntryfmt)
std::shared_ptr< ResultSet > QueryResult
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:135
uint32_t uint32
Definition Define.h:133
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
LanguageDesc const * GetLanguageDescByID(uint32 lang)
#define sObjectMgr
Definition ObjectMgr.h:1721
Language
@ LANG_UNIVERSAL
@ LANG_ADDON
@ EMOTE_ONESHOT_NONE
#define MAX_CHAT_MSG_TYPE
ChatMsg
@ CHAT_MSG_MONSTER_WHISPER
@ CHAT_MSG_SAY
@ CHAT_MSG_RAID_BOSS_WHISPER
@ CHAT_MSG_MONSTER_PARTY
@ CHAT_MSG_RAID_BOSS_EMOTE
@ CHAT_MSG_MONSTER_EMOTE
@ CHAT_MSG_ADDON
@ CHAT_MSG_MONSTER_YELL
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
@ WORLD_SEL_CREATURE_TEXT
static size_t BuildChatPacket(WorldPacket &data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string_view message, uint8 chatTag, std::string const &senderName="", std::string const &receiverName="", uint32 achievementId=0, bool gmMessage=false, std::string const &channelName="")
Definition Chat.cpp:193
WorldObject const * _target
CreatureTextBuilder(WorldObject const *obj, uint8 gender, ChatMsg msgtype, uint8 textGroup, uint32 id, uint32 language, WorldObject const *target)
WorldObject const * _source
size_t operator()(WorldPacket *data, LocaleConstant locale) const
LocaleCreatureTextMap mLocaleTextMap
std::string GetLocalizedChatString(uint32 entry, uint8 gender, uint8 textGroup, uint32 id, LocaleConstant locale) const
void SendChatPacket(WorldObject *source, Builder const &builder, ChatMsg msgType, WorldObject const *whisperTarget=nullptr, CreatureTextRange range=TEXT_RANGE_NORMAL, Team team=TEAM_OTHER, bool gmOnly=false) const
void SendEmote(Unit *source, Emote emote)
static CreatureTextMgr * instance()
uint32 SendChat(Creature *source, uint8 textGroup, WorldObject const *whisperTarget=nullptr, ChatMsg msgType=CHAT_MSG_ADDON, Language language=LANG_ADDON, CreatureTextRange range=TEXT_RANGE_NORMAL, uint32 sound=0, Team team=TEAM_OTHER, bool gmOnly=false, Player *srcPlr=nullptr)
bool TextExist(uint32 sourceEntry, uint8 textGroup)
void SendNonChatPacket(WorldObject *source, WorldPacket const *data, ChatMsg msgType, WorldObject const *whisperTarget, CreatureTextRange range, Team team, bool gmOnly) const
void SendSound(Creature *source, uint32 sound, ChatMsg msgType, WorldObject const *whisperTarget, CreatureTextRange range, Team team, bool gmOnly)
CreatureTextMap mTextMap
float GetRangeForChatType(ChatMsg msgType) const
CreatureTextRepeatIds GetTextRepeatGroup(uint8 textGroup)
void SetTextRepeatId(uint8 textGroup, uint8 id)
void ClearTextRepeatGroup(uint8 textGroup)
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
std::string GetString() const
Definition Field.cpp:125
float GetFloat() const
Definition Field.cpp:93
uint32 GetUInt32() const
Definition Field.cpp:61
Definition Group.h:165
iterator end()
iterator begin()
PlayerList const & GetPlayers() const
Definition Map.h:448
std::string ToString() const
static std::string_view GetLocaleString(std::vector< std::string > const &data, size_t locale)
Definition ObjectMgr.h:1525
static void AddLocaleString(std::string &&value, LocaleConstant localeConstant, std::vector< std::string > &data)
TypeID GetTypeId() const
Definition Object.h:93
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
static Player * ToPlayer(Object *o)
Definition Object.h:180
PlayerTextBuilder(WorldObject const *obj, WorldObject const *speaker, uint8 gender, ChatMsg msgtype, uint8 textGroup, uint32 id, uint32 language, WorldObject const *target)
WorldObject const * _talker
size_t operator()(WorldPacket *data, LocaleConstant locale) const
WorldObject const * _source
WorldObject const * _target
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
Definition Unit.h:769
Gender GetGender() const
Definition Unit.h:898
void HandleEmoteCommand(Emote emoteId)
Definition Unit.cpp:1568
Map * GetMap() const
Definition Object.h:449
std::string const & GetName() const
Definition Object.h:382
uint32 GetAreaId() const
Definition Object.h:374
virtual void SendMessageToSetInRange(WorldPacket const *data, float dist, bool self) const
Definition Object.cpp:1789
uint32 GetZoneId() const
Definition Object.h:373
#define sWorld
Definition World.h:900
std::unordered_map< uint32, WorldSession * > SessionMap
Definition World.h:553
@ CONFIG_LISTEN_RANGE_YELL
Definition World.h:191
@ CONFIG_LISTEN_RANGE_SAY
Definition World.h:189
@ CONFIG_LISTEN_RANGE_TEXTEMOTE
Definition World.h:190
auto SelectRandomWeightedContainerElement(C const &container, std::vector< double > weights) -> decltype(std::begin(container))
Definition Containers.h:125
std::string const & GetText(LocaleConstant locale=DEFAULT_LOCALE, uint8 gender=GENDER_MALE, bool forceGender=false) const
Definition ObjectMgr.h:496
CreatureTextRange TextRange
std::vector< std::string > Text