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 bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string
& msg
, uint32 lang
)
42 if (lang
!= LANG_ADDON
)
44 // strip invisible characters for non-addon messages
45 if(sWorld
.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING
))
46 stripLineInvisibleChars(msg
);
48 if (sWorld
.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY
) && GetSecurity() < SEC_MODERATOR
49 && !ChatHandler(this).isValidChatMessage(msg
.c_str()))
51 sLog
.outError("Player %s (GUID: %u) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName(),
52 GetPlayer()->GetGUIDLow(), msg
.c_str());
53 if (sWorld
.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK
))
62 void WorldSession::HandleMessagechatOpcode( WorldPacket
& recv_data
)
70 if(type
>= MAX_CHAT_MSG_TYPE
)
72 sLog
.outError("CHAT: Wrong message type received: %u", type
);
76 //sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang );
78 // prevent talking at unknown language (cheating)
79 LanguageDesc
const* langDesc
= GetLanguageDescByID(lang
);
82 SendNotification(LANG_UNKNOWN_LANGUAGE
);
85 if(langDesc
->skill_id
!= 0 && !_player
->HasSkill(langDesc
->skill_id
))
87 // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
88 Unit::AuraList
const& langAuras
= _player
->GetAurasByType(SPELL_AURA_COMPREHEND_LANGUAGE
);
89 bool foundAura
= false;
90 for(Unit::AuraList::const_iterator i
= langAuras
.begin();i
!= langAuras
.end(); ++i
)
92 if((*i
)->GetModifier()->m_miscvalue
== int32(lang
))
100 SendNotification(LANG_NOT_LEARNED_LANGUAGE
);
105 if(lang
== LANG_ADDON
)
107 // Disabled addon channel?
108 if(!sWorld
.getConfig(CONFIG_ADDON_CHANNEL
))
111 // LANG_ADDON should not be changed nor be affected by flood control
114 // send in universal language if player in .gmon mode (ignore spell effects)
115 if (_player
->isGameMaster())
116 lang
= LANG_UNIVERSAL
;
119 // send in universal language in two side iteration allowed mode
120 if (sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT
))
121 lang
= LANG_UNIVERSAL
;
128 case CHAT_MSG_RAID_LEADER
:
129 case CHAT_MSG_RAID_WARNING
:
130 // allow two side chat at group channel if two side group allowed
131 if(sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP
))
132 lang
= LANG_UNIVERSAL
;
135 case CHAT_MSG_OFFICER
:
136 // allow two side chat at guild channel if two side guild allowed
137 if(sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD
))
138 lang
= LANG_UNIVERSAL
;
143 // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
144 Unit::AuraList
const& ModLangAuras
= _player
->GetAurasByType(SPELL_AURA_MOD_LANGUAGE
);
145 if(!ModLangAuras
.empty())
146 lang
= ModLangAuras
.front()->GetModifier()->m_miscvalue
;
149 if (!_player
->CanSpeak())
151 std::string timeStr
= secsToTimeString(m_muteTime
- time(NULL
));
152 SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING
),timeStr
.c_str());
156 if (type
!= CHAT_MSG_AFK
&& type
!= CHAT_MSG_DND
)
157 GetPlayer()->UpdateSpeakTime();
166 std::string msg
= "";
172 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
175 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
181 if(type
== CHAT_MSG_SAY
)
182 GetPlayer()->Say(msg
, lang
);
183 else if(type
== CHAT_MSG_EMOTE
)
184 GetPlayer()->TextEmote(msg
);
185 else if(type
== CHAT_MSG_YELL
)
186 GetPlayer()->Yell(msg
, lang
);
189 case CHAT_MSG_WHISPER
:
195 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
201 if(!normalizePlayerName(to
))
203 WorldPacket
data(SMSG_CHAT_PLAYER_NOT_FOUND
, (to
.size()+1));
209 Player
*player
= objmgr
.GetPlayer(to
.c_str());
210 uint32 tSecurity
= GetSecurity();
211 uint32 pSecurity
= player
? player
->GetSession()->GetSecurity() : SEC_PLAYER
;
212 if (!player
|| (tSecurity
== SEC_PLAYER
&& pSecurity
> SEC_PLAYER
&& !player
->isAcceptWhispers()))
214 WorldPacket
data(SMSG_CHAT_PLAYER_NOT_FOUND
, (to
.size()+1));
220 if (!sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT
) && tSecurity
== SEC_PLAYER
&& pSecurity
== SEC_PLAYER
)
222 uint32 sidea
= GetPlayer()->GetTeam();
223 uint32 sideb
= player
->GetTeam();
226 WorldPacket
data(SMSG_CHAT_PLAYER_NOT_FOUND
, (to
.size()+1));
233 GetPlayer()->Whisper(msg
, lang
,player
->GetGUID());
238 std::string msg
= "";
244 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
247 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
253 // if player is in battleground, he cannot say to battleground members by /p
254 Group
*group
= GetPlayer()->GetOriginalGroup();
255 // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid, then return
256 if( !group
&& (!(group
= GetPlayer()->GetGroup()) || group
->isBGGroup()) )
260 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_PARTY
, lang
, NULL
, 0, msg
.c_str(),NULL
);
261 group
->BroadcastPacket(&data
, false, group
->GetMemberGroup(GetPlayer()->GetGUID()));
266 std::string msg
= "";
272 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
275 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
281 if (GetPlayer()->GetGuildId())
283 Guild
*guild
= objmgr
.GetGuildById(GetPlayer()->GetGuildId());
285 guild
->BroadcastToGuild(this, msg
, lang
== LANG_ADDON
? LANG_ADDON
: LANG_UNIVERSAL
);
290 case CHAT_MSG_OFFICER
:
292 std::string msg
= "";
298 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
301 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
307 if (GetPlayer()->GetGuildId())
309 Guild
*guild
= objmgr
.GetGuildById(GetPlayer()->GetGuildId());
311 guild
->BroadcastToOfficers(this, msg
, lang
== LANG_ADDON
? LANG_ADDON
: LANG_UNIVERSAL
);
323 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
326 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
332 // if player is in battleground, he cannot say to battleground members by /ra
333 Group
*group
= GetPlayer()->GetOriginalGroup();
334 // so if player hasn't OriginalGroup and his player->GetGroup() is BG raid or his group isn't raid, then return
335 if ((!group
&& !(group
= GetPlayer()->GetGroup())) || group
->isBGGroup() || !group
->isRaidGroup())
339 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID
, lang
, "", 0, msg
.c_str(),NULL
);
340 group
->BroadcastPacket(&data
, false);
342 case CHAT_MSG_RAID_LEADER
:
350 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
353 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
359 // if player is in battleground, he cannot say to battleground members by /ra
360 Group
*group
= GetPlayer()->GetOriginalGroup();
361 if ((!group
&& !(group
= GetPlayer()->GetGroup())) || group
->isBGGroup() || !group
->isRaidGroup())
365 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID_LEADER
, lang
, "", 0, msg
.c_str(),NULL
);
366 group
->BroadcastPacket(&data
, false);
368 case CHAT_MSG_RAID_WARNING
:
373 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
379 Group
*group
= GetPlayer()->GetGroup();
380 if(!group
|| !group
->isRaidGroup() || !(group
->IsLeader(GetPlayer()->GetGUID()) || group
->IsAssistant(GetPlayer()->GetGUID())))
384 //in battleground, raid warning is sent only to players in battleground - code is ok
385 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID_WARNING
, lang
, "", 0, msg
.c_str(),NULL
);
386 group
->BroadcastPacket(&data
, false);
389 case CHAT_MSG_BATTLEGROUND
:
394 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
400 //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
401 Group
*group
= GetPlayer()->GetGroup();
402 if(!group
|| !group
->isBGGroup())
406 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_BATTLEGROUND
, lang
, "", 0, msg
.c_str(),NULL
);
407 group
->BroadcastPacket(&data
, false);
410 case CHAT_MSG_BATTLEGROUND_LEADER
:
415 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
421 //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
422 Group
*group
= GetPlayer()->GetGroup();
423 if(!group
|| !group
->isBGGroup() || !group
->IsLeader(GetPlayer()->GetGUID()))
427 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_BATTLEGROUND_LEADER
, lang
, "", 0, msg
.c_str(),NULL
);
428 group
->BroadcastPacket(&data
, false);
431 case CHAT_MSG_CHANNEL
:
433 std::string channel
= "", msg
= "";
434 recv_data
>> channel
;
438 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
444 if(ChannelMgr
* cMgr
= channelMgr(_player
->GetTeam()))
446 if(Channel
*chn
= cMgr
->GetChannel(channel
,_player
))
447 chn
->Say(_player
->GetGUID(),msg
.c_str(),lang
);
456 if((msg
.empty() || !_player
->isAFK()) && !_player
->isInCombat() )
458 if(!_player
->isAFK())
461 msg
= GetMangosString(LANG_PLAYER_AFK_DEFAULT
);
462 _player
->afkMsg
= msg
;
464 _player
->ToggleAFK();
465 if(_player
->isAFK() && _player
->isDND())
466 _player
->ToggleDND();
475 if(msg
.empty() || !_player
->isDND())
477 if(!_player
->isDND())
480 msg
= GetMangosString(LANG_PLAYER_DND_DEFAULT
);
481 _player
->dndMsg
= msg
;
483 _player
->ToggleDND();
484 if(_player
->isDND() && _player
->isAFK())
485 _player
->ToggleAFK();
490 sLog
.outError("CHAT: unknown message type %u, lang: %u", type
, lang
);
495 void WorldSession::HandleEmoteOpcode( WorldPacket
& recv_data
)
497 if(!GetPlayer()->isAlive())
502 GetPlayer()->HandleEmoteCommand(emote
);
507 class EmoteChatBuilder
510 EmoteChatBuilder(Player
const& pl
, uint32 text_emote
, uint32 emote_num
, Unit
const* target
)
511 : i_player(pl
), i_text_emote(text_emote
), i_emote_num(emote_num
), i_target(target
) {}
513 void operator()(WorldPacket
& data
, int32 loc_idx
)
515 char const* nam
= i_target
? i_target
->GetNameForLocaleIdx(loc_idx
) : NULL
;
516 uint32 namlen
= (nam
? strlen(nam
) : 0) + 1;
518 data
.Initialize(SMSG_TEXT_EMOTE
, (20+namlen
));
519 data
<< i_player
.GetGUID();
520 data
<< (uint32
)i_text_emote
;
522 data
<< (uint32
)namlen
;
524 data
.append(nam
, namlen
);
530 Player
const& i_player
;
533 Unit
const* i_target
;
535 } // namespace MaNGOS
537 void WorldSession::HandleTextEmoteOpcode( WorldPacket
& recv_data
)
539 if(!GetPlayer()->isAlive())
542 if (!GetPlayer()->CanSpeak())
544 std::string timeStr
= secsToTimeString(m_muteTime
- time(NULL
));
545 SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING
),timeStr
.c_str());
549 uint32 text_emote
, emoteNum
;
552 recv_data
>> text_emote
;
553 recv_data
>> emoteNum
;
556 EmotesTextEntry
const *em
= sEmotesTextStore
.LookupEntry(text_emote
);
560 uint32 emote_anim
= em
->textid
;
564 case EMOTE_STATE_SLEEP
:
565 case EMOTE_STATE_SIT
:
566 case EMOTE_STATE_KNEEL
:
567 case EMOTE_ONESHOT_NONE
:
570 GetPlayer()->HandleEmoteCommand(emote_anim
);
574 Unit
* unit
= ObjectAccessor::GetUnit(*_player
, guid
);
576 CellPair p
= MaNGOS::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
579 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
582 MaNGOS::EmoteChatBuilder
emote_builder(*GetPlayer(), text_emote
, emoteNum
, unit
);
583 MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> emote_do(emote_builder
);
584 MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> > emote_worker(GetPlayer(),sWorld
.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE
),emote_do
);
585 TypeContainerVisitor
<MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> >, WorldTypeMapContainer
> message(emote_worker
);
586 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
587 cell_lock
->Visit(cell_lock
, message
, *GetPlayer()->GetMap());
589 GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE
, text_emote
, 0, unit
);
591 //Send scripted event call
592 if (unit
&& unit
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)unit
)->AI())
593 ((Creature
*)unit
)->AI()->ReceiveEmote(GetPlayer(),text_emote
);
596 void WorldSession::HandleChatIgnoredOpcode(WorldPacket
& recv_data
)
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
);