2 * Copyright (C) 2005-2010 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_BOOL_CHAT_FAKE_MESSAGE_PREVENTING
))
46 stripLineInvisibleChars(msg
);
48 if (sWorld
.getConfig(CONFIG_UINT32_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_UINT32_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_BOOL_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_BOOL_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_BOOL_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_BOOL_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();
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 SendPlayerNotFoundNotice(to
);
207 Player
*player
= sObjectMgr
.GetPlayer(to
.c_str());
208 uint32 tSecurity
= GetSecurity();
209 uint32 pSecurity
= player
? player
->GetSession()->GetSecurity() : SEC_PLAYER
;
210 if (!player
|| (tSecurity
== SEC_PLAYER
&& pSecurity
> SEC_PLAYER
&& !player
->isAcceptWhispers()))
212 SendPlayerNotFoundNotice(to
);
216 if (!sWorld
.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT
) && tSecurity
== SEC_PLAYER
&& pSecurity
== SEC_PLAYER
)
218 uint32 sidea
= GetPlayer()->GetTeam();
219 uint32 sideb
= player
->GetTeam();
222 SendPlayerNotFoundNotice(to
);
227 GetPlayer()->Whisper(msg
, lang
, player
->GetGUID());
231 case CHAT_MSG_PARTY_LEADER
:
239 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
242 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
248 // if player is in battleground, he cannot say to battleground members by /p
249 Group
*group
= GetPlayer()->GetOriginalGroup();
252 group
= _player
->GetGroup();
253 if(!group
|| group
->isBGGroup())
257 if((type
== CHAT_MSG_PARTY_LEADER
) && !group
->IsLeader(_player
->GetGUID()))
261 ChatHandler::FillMessageData(&data
, this, type
, lang
, NULL
, 0, msg
.c_str(), NULL
);
262 group
->BroadcastPacket(&data
, false, group
->GetMemberGroup(GetPlayer()->GetGUID()));
273 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
276 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
282 if (GetPlayer()->GetGuildId())
283 if (Guild
*guild
= sObjectMgr
.GetGuildById(GetPlayer()->GetGuildId()))
284 guild
->BroadcastToGuild(this, msg
, lang
== LANG_ADDON
? LANG_ADDON
: LANG_UNIVERSAL
);
287 case CHAT_MSG_OFFICER
:
295 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
298 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
304 if (GetPlayer()->GetGuildId())
305 if (Guild
*guild
= sObjectMgr
.GetGuildById(GetPlayer()->GetGuildId()))
306 guild
->BroadcastToOfficers(this, msg
, lang
== LANG_ADDON
? LANG_ADDON
: LANG_UNIVERSAL
);
317 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
320 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
326 // if player is in battleground, he cannot say to battleground members by /ra
327 Group
*group
= GetPlayer()->GetOriginalGroup();
330 group
= GetPlayer()->GetGroup();
331 if(!group
|| group
->isBGGroup() || !group
->isRaidGroup())
336 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID
, lang
, "", 0, msg
.c_str(), NULL
);
337 group
->BroadcastPacket(&data
, false);
339 case CHAT_MSG_RAID_LEADER
:
347 if (ChatHandler(this).ParseCommands(msg
.c_str()) > 0)
350 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
356 // if player is in battleground, he cannot say to battleground members by /ra
357 Group
*group
= GetPlayer()->GetOriginalGroup();
360 group
= GetPlayer()->GetGroup();
361 if(!group
|| group
->isBGGroup() || !group
->isRaidGroup() || !group
->IsLeader(_player
->GetGUID()))
366 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID_LEADER
, lang
, "", 0, msg
.c_str(), NULL
);
367 group
->BroadcastPacket(&data
, false);
370 case CHAT_MSG_RAID_WARNING
:
375 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
381 Group
*group
= GetPlayer()->GetGroup();
382 if(!group
|| !group
->isRaidGroup() || !(group
->IsLeader(GetPlayer()->GetGUID()) || group
->IsAssistant(GetPlayer()->GetGUID())))
386 //in battleground, raid warning is sent only to players in battleground - code is ok
387 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_RAID_WARNING
, lang
, "", 0, msg
.c_str(), NULL
);
388 group
->BroadcastPacket(&data
, false);
391 case CHAT_MSG_BATTLEGROUND
:
396 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
402 // battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
403 Group
*group
= GetPlayer()->GetGroup();
404 if(!group
|| !group
->isBGGroup())
408 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_BATTLEGROUND
, lang
, "", 0, msg
.c_str(), NULL
);
409 group
->BroadcastPacket(&data
, false);
412 case CHAT_MSG_BATTLEGROUND_LEADER
:
417 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
423 // battleground raid is always in Player->GetGroup(), never in GetOriginalGroup()
424 Group
*group
= GetPlayer()->GetGroup();
425 if(!group
|| !group
->isBGGroup() || !group
->IsLeader(GetPlayer()->GetGUID()))
429 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_BATTLEGROUND_LEADER
, lang
, "", 0, msg
.c_str(), NULL
);
430 group
->BroadcastPacket(&data
, false);
433 case CHAT_MSG_CHANNEL
:
435 std::string channel
, msg
;
436 recv_data
>> channel
;
439 if (!processChatmessageFurtherAfterSecurityChecks(msg
, lang
))
445 if(ChannelMgr
* cMgr
= channelMgr(_player
->GetTeam()))
446 if(Channel
*chn
= cMgr
->GetChannel(channel
, _player
))
447 chn
->Say(_player
->GetGUID(), msg
.c_str(), lang
);
455 if((msg
.empty() || !_player
->isAFK()) && !_player
->isInCombat() )
457 if(!_player
->isAFK())
460 msg
= GetMangosString(LANG_PLAYER_AFK_DEFAULT
);
461 _player
->afkMsg
= msg
;
463 _player
->ToggleAFK();
464 if(_player
->isAFK() && _player
->isDND())
465 _player
->ToggleDND();
474 if(msg
.empty() || !_player
->isDND())
476 if(!_player
->isDND())
479 msg
= GetMangosString(LANG_PLAYER_DND_DEFAULT
);
480 _player
->dndMsg
= msg
;
482 _player
->ToggleDND();
483 if(_player
->isDND() && _player
->isAFK())
484 _player
->ToggleAFK();
489 sLog
.outError("CHAT: unknown message type %u, lang: %u", type
, lang
);
494 void WorldSession::HandleEmoteOpcode( WorldPacket
& recv_data
)
496 if(!GetPlayer()->isAlive())
501 GetPlayer()->HandleEmoteCommand(emote
);
506 class EmoteChatBuilder
509 EmoteChatBuilder(Player
const& pl
, uint32 text_emote
, uint32 emote_num
, Unit
const* target
)
510 : i_player(pl
), i_text_emote(text_emote
), i_emote_num(emote_num
), i_target(target
) {}
512 void operator()(WorldPacket
& data
, int32 loc_idx
)
514 char const* nam
= i_target
? i_target
->GetNameForLocaleIdx(loc_idx
) : NULL
;
515 uint32 namlen
= (nam
? strlen(nam
) : 0) + 1;
517 data
.Initialize(SMSG_TEXT_EMOTE
, (20+namlen
));
518 data
<< i_player
.GetGUID();
519 data
<< (uint32
)i_text_emote
;
521 data
<< (uint32
)namlen
;
523 data
.append(nam
, namlen
);
529 Player
const& i_player
;
532 Unit
const* i_target
;
534 } // namespace MaNGOS
536 void WorldSession::HandleTextEmoteOpcode( WorldPacket
& recv_data
)
538 if(!GetPlayer()->isAlive())
541 if (!GetPlayer()->CanSpeak())
543 std::string timeStr
= secsToTimeString(m_muteTime
- time(NULL
));
544 SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING
), timeStr
.c_str());
548 uint32 text_emote
, emoteNum
;
551 recv_data
>> text_emote
;
552 recv_data
>> emoteNum
;
555 EmotesTextEntry
const *em
= sEmotesTextStore
.LookupEntry(text_emote
);
559 uint32 emote_anim
= em
->textid
;
563 case EMOTE_STATE_SLEEP
:
564 case EMOTE_STATE_SIT
:
565 case EMOTE_STATE_KNEEL
:
566 case EMOTE_ONESHOT_NONE
:
569 GetPlayer()->HandleEmoteCommand(emote_anim
);
573 Unit
* unit
= ObjectAccessor::GetUnit(*_player
, guid
);
575 CellPair p
= MaNGOS::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
578 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
581 MaNGOS::EmoteChatBuilder
emote_builder(*GetPlayer(), text_emote
, emoteNum
, unit
);
582 MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> emote_do(emote_builder
);
583 MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> > emote_worker(GetPlayer(), sWorld
.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE
), emote_do
);
584 TypeContainerVisitor
<MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::EmoteChatBuilder
> >, WorldTypeMapContainer
> message(emote_worker
);
585 cell
.Visit(p
, message
, *GetPlayer()->GetMap(), *GetPlayer(), sWorld
.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE
));
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
)
598 //sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED");
601 recv_data
>> unk
; // probably related to spam reporting
603 Player
*player
= sObjectMgr
.GetPlayer(iguid
);
604 if(!player
|| !player
->GetSession())
608 ChatHandler::FillMessageData(&data
, this, CHAT_MSG_IGNORED
, LANG_UNIVERSAL
, NULL
, GetPlayer()->GetGUID(), GetPlayer()->GetName(), NULL
);
609 player
->GetSession()->SendPacket(&data
);
612 void WorldSession::SendPlayerNotFoundNotice(std::string name
)
614 WorldPacket
data(SMSG_CHAT_PLAYER_NOT_FOUND
, name
.size()+1);