2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "WorldPacket.h"
22 #include "WorldSession.h"
25 #include "ObjectMgr.h"
27 #include "Database/DatabaseEnv.h"
28 #include "ChannelMgr.h"
31 #include "ObjectAccessor.h"
32 #include "ScriptCalls.h"
34 #include "SpellAuras.h"
37 #include "GridNotifiersImpl.h"
40 void WorldSession::HandleMessagechatOpcode( WorldPacket
& recv_data
)
42 CHECK_PACKET_SIZE(recv_data
,4+4+1);
50 if(type
>= MAX_CHAT_MSG_TYPE
)
52 sLog
.outError("CHAT: Wrong message type received: %u", type
);
56 //sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang );
58 // prevent talking at unknown language (cheating)
59 LanguageDesc
const* langDesc
= GetLanguageDescByID(lang
);
62 SendNotification(LANG_UNKNOWN_LANGUAGE
);
65 if(langDesc
->skill_id
!= 0 && !_player
->HasSkill(langDesc
->skill_id
))
67 // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
68 Unit::AuraList
const& langAuras
= _player
->GetAurasByType(SPELL_AURA_COMPREHEND_LANGUAGE
);
69 bool foundAura
= false;
70 for(Unit::AuraList::const_iterator i
= langAuras
.begin();i
!= langAuras
.end(); ++i
)
72 if((*i
)->GetModifier()->m_miscvalue
== int32(lang
))
80 SendNotification(LANG_NOT_LEARNED_LANGUAGE
);
85 if(lang
== LANG_ADDON
)
87 // Disabled addon channel?
88 if(!sWorld
.getConfig(CONFIG_ADDON_CHANNEL
))
91 // LANG_ADDON should not be changed nor be affected by flood control
94 // send in universal language if player in .gmon mode (ignore spell effects)
95 if (_player
->isGameMaster())
96 lang
= LANG_UNIVERSAL
;
99 // send in universal language in two side iteration allowed mode
100 if (sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT
))
101 lang
= LANG_UNIVERSAL
;
108 case CHAT_MSG_RAID_LEADER
:
109 case CHAT_MSG_RAID_WARNING
:
110 // allow two side chat at group channel if two side group allowed
111 if(sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP
))
112 lang
= LANG_UNIVERSAL
;
115 case CHAT_MSG_OFFICER
:
116 // allow two side chat at guild channel if two side guild allowed
117 if(sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD
))
118 lang
= LANG_UNIVERSAL
;
123 // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
124 Unit::AuraList
const& ModLangAuras
= _player
->GetAurasByType(SPELL_AURA_MOD_LANGUAGE
);
125 if(!ModLangAuras
.empty())
126 lang
= ModLangAuras
.front()->GetModifier()->m_miscvalue
;
129 if (!_player
->CanSpeak())
131 std::string timeStr
= secsToTimeString(m_muteTime
- time(NULL
));
132 SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING
),timeStr
.c_str());
136 if (type
!= CHAT_MSG_AFK
&& type
!= CHAT_MSG_DND
)
137 GetPlayer()->UpdateSpeakTime();
146 std::string msg
= "";
152 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
155 // strip invisible characters for non-addon messages
156 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
157 stripLineInvisibleChars(msg
);
162 if(type
== CHAT_MSG_SAY
)
163 GetPlayer()->Say(msg
, lang
);
164 else if(type
== CHAT_MSG_EMOTE
)
165 GetPlayer()->TextEmote(msg
);
166 else if(type
== CHAT_MSG_YELL
)
167 GetPlayer()->Yell(msg
, lang
);
170 case CHAT_MSG_WHISPER
:
174 CHECK_PACKET_SIZE(recv_data
,4+4+(to
.size()+1)+1);
177 // strip invisible characters for non-addon messages
178 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
179 stripLineInvisibleChars(msg
);
184 if(!normalizePlayerName(to
))
186 WorldPacket
data(SMSG_CHAT_PLAYER_NOT_FOUND
, (to
.size()+1));
192 Player
*player
= objmgr
.GetPlayer(to
.c_str());
193 uint32 tSecurity
= GetSecurity();
194 uint32 pSecurity
= player
? player
->GetSession()->GetSecurity() : SEC_PLAYER
;
195 if (!player
|| (tSecurity
== SEC_PLAYER
&& pSecurity
> SEC_PLAYER
&& !player
->isAcceptWhispers()))
197 WorldPacket
data(SMSG_CHAT_PLAYER_NOT_FOUND
, (to
.size()+1));
203 if (!sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT
) && tSecurity
== SEC_PLAYER
&& pSecurity
== SEC_PLAYER
)
205 uint32 sidea
= GetPlayer()->GetTeam();
206 uint32 sideb
= player
->GetTeam();
209 WorldPacket
data(SMSG_CHAT_PLAYER_NOT_FOUND
, (to
.size()+1));
216 GetPlayer()->Whisper(msg
, lang
,player
->GetGUID());
221 std::string msg
= "";
227 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
230 // strip invisible characters for non-addon messages
231 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
232 stripLineInvisibleChars(msg
);
237 // if player is in battleground, he cannot say to battleground members by /p
238 Group
*group
= GetPlayer()->GetOriginalGroup();
239 // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid, then return
240 if( !group
&& (!(group
= GetPlayer()->GetGroup()) || group
->isBGGroup()) )
244 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_PARTY
, lang
, NULL
, 0, msg
.c_str(),NULL
);
245 group
->BroadcastPacket(&data
, false, group
->GetMemberGroup(GetPlayer()->GetGUID()));
250 std::string msg
= "";
256 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
259 // strip invisible characters for non-addon messages
260 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
261 stripLineInvisibleChars(msg
);
266 if (GetPlayer()->GetGuildId())
268 Guild
*guild
= objmgr
.GetGuildById(GetPlayer()->GetGuildId());
270 guild
->BroadcastToGuild(this, msg
, lang
== LANG_ADDON
? LANG_ADDON
: LANG_UNIVERSAL
);
275 case CHAT_MSG_OFFICER
:
277 std::string msg
= "";
283 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
286 // strip invisible characters for non-addon messages
287 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
288 stripLineInvisibleChars(msg
);
293 if (GetPlayer()->GetGuildId())
295 Guild
*guild
= objmgr
.GetGuildById(GetPlayer()->GetGuildId());
297 guild
->BroadcastToOfficers(this, msg
, lang
== LANG_ADDON
? LANG_ADDON
: LANG_UNIVERSAL
);
309 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
312 // strip invisible characters for non-addon messages
313 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
314 stripLineInvisibleChars(msg
);
319 // if player is in battleground, he cannot say to battleground members by /ra
320 Group
*group
= GetPlayer()->GetOriginalGroup();
321 // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid or his group isn't raid, then return
322 if ((!group
&& !(group
= GetPlayer()->GetGroup())) || group
->isBGGroup() || !group
->isRaidGroup())
326 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID
, lang
, "", 0, msg
.c_str(),NULL
);
327 group
->BroadcastPacket(&data
, false);
329 case CHAT_MSG_RAID_LEADER
:
337 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
340 // strip invisible characters for non-addon messages
341 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
342 stripLineInvisibleChars(msg
);
347 // if player is in battleground, he cannot say to battleground members by /ra
348 Group
*group
= GetPlayer()->GetOriginalGroup();
349 if ((!group
&& !(group
= GetPlayer()->GetGroup())) || group
->isBGGroup() || !group
->isRaidGroup())
353 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID_LEADER
, lang
, "", 0, msg
.c_str(),NULL
);
354 group
->BroadcastPacket(&data
, false);
356 case CHAT_MSG_RAID_WARNING
:
361 // strip invisible characters for non-addon messages
362 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
363 stripLineInvisibleChars(msg
);
368 Group
*group
= GetPlayer()->GetGroup();
369 if(!group
|| !group
->isRaidGroup() || !(group
->IsLeader(GetPlayer()->GetGUID()) || group
->IsAssistant(GetPlayer()->GetGUID())))
373 //in battleground, raid warning is sent only to players in battleground - code is ok
374 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID_WARNING
, lang
, "", 0, msg
.c_str(),NULL
);
375 group
->BroadcastPacket(&data
, false);
378 case CHAT_MSG_BATTLEGROUND
:
383 // strip invisible characters for non-addon messages
384 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
385 stripLineInvisibleChars(msg
);
390 //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
391 Group
*group
= GetPlayer()->GetGroup();
392 if(!group
|| !group
->isBGGroup())
396 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_BATTLEGROUND
, lang
, "", 0, msg
.c_str(),NULL
);
397 group
->BroadcastPacket(&data
, false);
400 case CHAT_MSG_BATTLEGROUND_LEADER
:
405 // strip invisible characters for non-addon messages
406 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
407 stripLineInvisibleChars(msg
);
412 //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
413 Group
*group
= GetPlayer()->GetGroup();
414 if(!group
|| !group
->isBGGroup() || !group
->IsLeader(GetPlayer()->GetGUID()))
418 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_BATTLEGROUND_LEADER
, lang
, "", 0, msg
.c_str(),NULL
);
419 group
->BroadcastPacket(&data
, false);
422 case CHAT_MSG_CHANNEL
:
424 std::string channel
= "", msg
= "";
425 recv_data
>> channel
;
428 CHECK_PACKET_SIZE(recv_data
,4+4+(channel
.size()+1)+1);
432 // strip invisible characters for non-addon messages
433 if (lang
!= LANG_ADDON
&& sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
434 stripLineInvisibleChars(msg
);
439 if(ChannelMgr
* cMgr
= channelMgr(_player
->GetTeam()))
441 if(Channel
*chn
= cMgr
->GetChannel(channel
,_player
))
442 chn
->Say(_player
->GetGUID(),msg
.c_str(),lang
);
451 if((msg
.empty() || !_player
->isAFK()) && !_player
->isInCombat() )
453 if(!_player
->isAFK())
456 msg
= GetMangosString(LANG_PLAYER_AFK_DEFAULT
);
457 _player
->afkMsg
= msg
;
459 _player
->ToggleAFK();
460 if(_player
->isAFK() && _player
->isDND())
461 _player
->ToggleDND();
470 if(msg
.empty() || !_player
->isDND())
472 if(!_player
->isDND())
475 msg
= GetMangosString(LANG_PLAYER_DND_DEFAULT
);
476 _player
->dndMsg
= msg
;
478 _player
->ToggleDND();
479 if(_player
->isDND() && _player
->isAFK())
480 _player
->ToggleAFK();
485 sLog
.outError("CHAT: unknown message type %u, lang: %u", type
, lang
);
490 void WorldSession::HandleEmoteOpcode( WorldPacket
& recv_data
)
492 if(!GetPlayer()->isAlive())
494 CHECK_PACKET_SIZE(recv_data
,4);
498 GetPlayer()->HandleEmoteCommand(emote
);
503 class EmoteChatBuilder
506 EmoteChatBuilder(Player
const& pl
, uint32 text_emote
, uint32 emote_num
, Unit
const* target
)
507 : i_player(pl
), i_text_emote(text_emote
), i_emote_num(emote_num
), i_target(target
) {}
509 void operator()(WorldPacket
& data
, int32 loc_idx
)
511 char const* nam
= i_target
? i_target
->GetNameForLocaleIdx(loc_idx
) : NULL
;
512 uint32 namlen
= (nam
? strlen(nam
) : 0) + 1;
514 data
.Initialize(SMSG_TEXT_EMOTE
, (20+namlen
));
515 data
<< i_player
.GetGUID();
516 data
<< (uint32
)i_text_emote
;
518 data
<< (uint32
)namlen
;
520 data
.append(nam
, namlen
);
526 Player
const& i_player
;
529 Unit
const* i_target
;
531 } // namespace MaNGOS
533 void WorldSession::HandleTextEmoteOpcode( WorldPacket
& recv_data
)
535 if(!GetPlayer()->isAlive())
538 if (!GetPlayer()->CanSpeak())
540 std::string timeStr
= secsToTimeString(m_muteTime
- time(NULL
));
541 SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING
),timeStr
.c_str());
545 CHECK_PACKET_SIZE(recv_data
,4+4+8);
547 uint32 text_emote
, emoteNum
;
550 recv_data
>> text_emote
;
551 recv_data
>> emoteNum
;
554 EmotesTextEntry
const *em
= sEmotesTextStore
.LookupEntry(text_emote
);
558 uint32 emote_anim
= em
->textid
;
562 case EMOTE_STATE_SLEEP
:
563 case EMOTE_STATE_SIT
:
564 case EMOTE_STATE_KNEEL
:
565 case EMOTE_ONESHOT_NONE
:
568 GetPlayer()->HandleEmoteCommand(emote_anim
);
572 Unit
* unit
= ObjectAccessor::GetUnit(*_player
, guid
);
574 CellPair p
= MaNGOS::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
577 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
580 MaNGOS::EmoteChatBuilder
emote_builder(*GetPlayer(), text_emote
, emoteNum
, unit
);
581 MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> emote_do(emote_builder
);
582 MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> > emote_worker(GetPlayer(),sWorld
.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE
),emote_do
);
583 TypeContainerVisitor
<MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> >, WorldTypeMapContainer
> message(emote_worker
);
584 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
585 cell_lock
->Visit(cell_lock
, message
, *GetPlayer()->GetMap());
587 GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE
, text_emote
, 0, unit
);
589 //Send scripted event call
590 if (unit
&& unit
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)unit
)->AI())
591 ((Creature
*)unit
)->AI()->ReceiveEmote(GetPlayer(),text_emote
);
594 void WorldSession::HandleChatIgnoredOpcode(WorldPacket
& recv_data
)
596 CHECK_PACKET_SIZE(recv_data
, 8+1);
600 //sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED");
603 recv_data
>> unk
; // probably related to spam reporting
605 Player
*player
= objmgr
.GetPlayer(iguid
);
606 if(!player
|| !player
->GetSession())
610 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_IGNORED
, LANG_UNIVERSAL
, NULL
, GetPlayer()->GetGUID(), GetPlayer()->GetName(),NULL
);
611 player
->GetSession()->SendPacket(&data
);