root/trunk/src/game/ChatHandler.cpp @ 39

Revision 39, 18.1 kB (checked in by yumileroy, 17 years ago)

[svn] * Various small changes here and there.
* Implementing MangChat? IRC system.
* Added new config option, MAX_WHO, can be used to set the limit of characters being sent in a /who request from client.

Original author: XTZGZoReX
Date: 2008-10-12 14:03:38-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include "Common.h"
20#include "Log.h"
21#include "WorldPacket.h"
22#include "WorldSession.h"
23#include "World.h"
24#include "Opcodes.h"
25#include "ObjectMgr.h"
26#include "Chat.h"
27#include "Database/DatabaseEnv.h"
28#include "ChannelMgr.h"
29#include "Group.h"
30#include "Guild.h"
31#include "MapManager.h"
32#include "ObjectAccessor.h"
33#include "ScriptCalls.h"
34#include "Player.h"
35#include "SpellAuras.h"
36#include "Language.h"
37#include "IRCClient.h"
38#include "Util.h"
39
40void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
41{
42    CHECK_PACKET_SIZE(recv_data,4+4+1);
43
44    uint32 type;
45    uint32 lang;
46
47    recv_data >> type;
48    recv_data >> lang;
49
50    if(type >= MAX_CHAT_MSG_TYPE)
51    {
52        sLog.outError("CHAT: Wrong message type received: %u", type);
53        return;
54    }
55
56    //sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang );
57
58    // prevent talking at unknown language (cheating)
59    LanguageDesc const* langDesc = GetLanguageDescByID(lang);
60    if(!langDesc)
61    {
62        SendNotification(LANG_UNKNOWN_LANGUAGE);
63        return;
64    }
65    if(langDesc->skill_id != 0 && !_player->HasSkill(langDesc->skill_id))
66    {
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)
71        {
72            if((*i)->GetModifier()->m_miscvalue == lang)
73            {
74                foundAura = true;
75                break;
76            }
77        }
78        if(!foundAura)
79        {
80            SendNotification(LANG_NOT_LEARNED_LANGUAGE);
81            return;
82        }
83    }
84
85    if(lang == LANG_ADDON)
86    {
87        // Disabled addon channel?
88        if(!sWorld.getConfig(CONFIG_ADDON_CHANNEL))
89            return;
90    }
91    // LANG_ADDON should not be changed nor be affected by flood control
92    else
93    {
94        // send in universal language if player in .gmon mode (ignore spell effects)
95        if (_player->isGameMaster())
96            lang = LANG_UNIVERSAL;
97        else
98        {
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;
102            else
103            {
104                switch(type)
105                {
106                    case CHAT_MSG_PARTY:
107                    case CHAT_MSG_RAID:
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;
113                        break;
114                    case CHAT_MSG_GUILD:
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;
119                        break;
120                }
121            }
122
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;
127        }
128
129        if (!_player->CanSpeak())
130        {
131            std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
132            SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
133            return;
134        }
135
136        if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND)
137            GetPlayer()->UpdateSpeakTime();
138    }
139
140    switch(type)
141    {
142        case CHAT_MSG_SAY:
143        case CHAT_MSG_EMOTE:
144        case CHAT_MSG_YELL:
145        {
146            std::string msg = "";
147            recv_data >> msg;
148
149            if(msg.empty())
150                break;
151
152            if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
153                break;
154
155            // strip invisible characters for non-addon messages
156            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
157                stripLineInvisibleChars(msg);
158
159            if(msg.empty())
160                break;
161
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);
168        } break;
169
170        case CHAT_MSG_WHISPER:
171        {
172            std::string to, msg;
173            recv_data >> to;
174            CHECK_PACKET_SIZE(recv_data,4+4+(to.size()+1)+1);
175            recv_data >> msg;
176
177            // strip invisible characters for non-addon messages
178            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
179                stripLineInvisibleChars(msg);
180
181            if(msg.empty())
182                break;
183
184            if(!normalizePlayerName(to))
185            {
186                WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
187                data<<to;
188                SendPacket(&data);
189                break;
190            }
191
192            Player *player = objmgr.GetPlayer(to.c_str());
193            uint32 tSecurity = GetSecurity();
194            uint32 pSecurity = player ? player->GetSession()->GetSecurity() : 0;
195            if(!player || tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers())
196            {
197                WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
198                data<<to;
199                SendPacket(&data);
200                return;
201            }
202
203            if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && tSecurity == SEC_PLAYER && pSecurity == SEC_PLAYER )
204            {
205                uint32 sidea = GetPlayer()->GetTeam();
206                uint32 sideb = player->GetTeam();
207                if( sidea != sideb )
208                {
209                    WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
210                    data<<to;
211                    SendPacket(&data);
212                    return;
213                }
214            }
215
216            GetPlayer()->Whisper(msg, lang,player->GetGUID());
217        } break;
218
219        case CHAT_MSG_PARTY:
220        {
221            std::string msg = "";
222            recv_data >> msg;
223
224            if(msg.empty())
225                break;
226
227            if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
228                break;
229
230            // strip invisible characters for non-addon messages
231            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
232                stripLineInvisibleChars(msg);
233
234            if(msg.empty())
235                break;
236
237            Group *group = GetPlayer()->GetGroup();
238            if(!group)
239                return;
240
241            WorldPacket data;
242            ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL);
243            group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID()));
244        }
245        break;
246        case CHAT_MSG_GUILD:
247        {
248            std::string msg = "";
249            recv_data >> msg;
250
251            if(msg.empty())
252                break;
253
254            if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
255                break;
256
257            // strip invisible characters for non-addon messages
258            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
259                stripLineInvisibleChars(msg);
260
261            if(msg.empty())
262                break;
263
264            if (GetPlayer()->GetGuildId())
265            {
266                Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
267                if (guild)
268                    guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
269            }
270
271            break;
272        }
273        case CHAT_MSG_OFFICER:
274        {
275            std::string msg = "";
276            recv_data >> msg;
277
278            if(msg.empty())
279                break;
280
281            if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
282                break;
283
284            // strip invisible characters for non-addon messages
285            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
286                stripLineInvisibleChars(msg);
287
288            if(msg.empty())
289                break;
290
291            if (GetPlayer()->GetGuildId())
292            {
293                Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
294                if (guild)
295                    guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
296            }
297            break;
298        }
299        case CHAT_MSG_RAID:
300        {
301            std::string msg="";
302            recv_data >> msg;
303
304            if(msg.empty())
305                break;
306
307            if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
308                break;
309
310            // strip invisible characters for non-addon messages
311            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
312                stripLineInvisibleChars(msg);
313
314            if(msg.empty())
315                break;
316
317            Group *group = GetPlayer()->GetGroup();
318            if(!group || !group->isRaidGroup())
319                return;
320
321            WorldPacket data;
322            ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL);
323            group->BroadcastPacket(&data);
324        } break;
325        case CHAT_MSG_RAID_LEADER:
326        {
327            std::string msg="";
328            recv_data >> msg;
329
330            if(msg.empty())
331                break;
332
333            if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
334                break;
335
336            // strip invisible characters for non-addon messages
337            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
338                stripLineInvisibleChars(msg);
339
340            if(msg.empty())
341                break;
342
343            Group *group = GetPlayer()->GetGroup();
344            if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
345                return;
346
347            WorldPacket data;
348            ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL);
349            group->BroadcastPacket(&data);
350        } break;
351        case CHAT_MSG_RAID_WARNING:
352        {
353            std::string msg="";
354            recv_data >> msg;
355
356            // strip invisible characters for non-addon messages
357            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
358                stripLineInvisibleChars(msg);
359
360            if(msg.empty())
361                break;
362
363            Group *group = GetPlayer()->GetGroup();
364            if(!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())))
365                return;
366
367            WorldPacket data;
368            ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL);
369            group->BroadcastPacket(&data);
370        } break;
371
372        case CHAT_MSG_BATTLEGROUND:
373        {
374            std::string msg="";
375            recv_data >> msg;
376
377            // strip invisible characters for non-addon messages
378            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
379                stripLineInvisibleChars(msg);
380
381            if(msg.empty())
382                break;
383
384            Group *group = GetPlayer()->GetGroup();
385            if(!group || !group->isRaidGroup())
386                return;
387
388            WorldPacket data;
389            ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL);
390            group->BroadcastPacket(&data);
391        } break;
392
393        case CHAT_MSG_BATTLEGROUND_LEADER:
394        {
395            std::string msg="";
396            recv_data >> msg;
397
398            // strip invisible characters for non-addon messages
399            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
400                stripLineInvisibleChars(msg);
401
402            if(msg.empty())
403                break;
404
405            Group *group = GetPlayer()->GetGroup();
406            if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
407                return;
408
409            WorldPacket data;
410            ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL);
411            group->BroadcastPacket(&data);
412        } break;
413
414        case CHAT_MSG_CHANNEL:
415        {
416            std::string channel = "", msg = "";
417            recv_data >> channel;
418
419            // recheck
420            CHECK_PACKET_SIZE(recv_data,4+4+(channel.size()+1)+1);
421
422            recv_data >> msg;
423
424            // strip invisible characters for non-addon messages
425            if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
426                stripLineInvisibleChars(msg);
427
428            if(msg.empty())
429                break;
430
431            sIRC.Send_WoW_IRC(_player, channel, msg);
432
433            if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
434            {
435                if(Channel *chn = cMgr->GetChannel(channel,_player))
436                    chn->Say(_player->GetGUID(),msg.c_str(),lang);
437            }
438        } break;
439
440        case CHAT_MSG_AFK:
441        {
442            std::string msg;
443            recv_data >> msg;
444
445            if((msg.empty() || !_player->isAFK()) && !_player->isInCombat() )
446            {
447                if(!_player->isAFK())
448                {
449                    if(msg.empty())
450                        msg  = GetMangosString(LANG_PLAYER_AFK_DEFAULT);
451                    _player->afkMsg = msg;
452                }
453                _player->ToggleAFK();
454                if(_player->isAFK() && _player->isDND())
455                    _player->ToggleDND();
456            }
457        } break;
458
459        case CHAT_MSG_DND:
460        {
461            std::string msg;
462            recv_data >> msg;
463
464            if(msg.empty() || !_player->isDND())
465            {
466                if(!_player->isDND())
467                {
468                    if(msg.empty())
469                        msg  = GetMangosString(LANG_PLAYER_DND_DEFAULT);
470                    _player->dndMsg = msg;
471                }
472                _player->ToggleDND();
473                if(_player->isDND() && _player->isAFK())
474                    _player->ToggleAFK();
475            }
476        } break;
477
478        default:
479            sLog.outError("CHAT: unknown message type %u, lang: %u", type, lang);
480            break;
481    }
482}
483
484void WorldSession::HandleEmoteOpcode( WorldPacket & recv_data )
485{
486    if(!GetPlayer()->isAlive())
487        return;
488    CHECK_PACKET_SIZE(recv_data,4);
489
490    uint32 emote;
491    recv_data >> emote;
492    GetPlayer()->HandleEmoteCommand(emote);
493}
494
495void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
496{
497    if(!GetPlayer()->isAlive())
498        return;
499
500    if (!GetPlayer()->CanSpeak())
501    {
502        std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
503        SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
504        return;
505    }
506
507    CHECK_PACKET_SIZE(recv_data,4+4+8);
508
509    uint32 text_emote, emoteNum;
510    uint64 guid;
511
512    recv_data >> text_emote;
513    recv_data >> emoteNum;
514    recv_data >> guid;
515
516    const char *nam = 0;
517    uint32 namlen = 1;
518
519    Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
520    Creature *pCreature = dynamic_cast<Creature *>(unit);
521    if(unit)
522    {
523        nam = unit->GetName();
524        namlen = (nam ? strlen(nam) : 0) + 1;
525    }
526
527    EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote);
528    if (em)
529    {
530        uint32 emote_anim = em->textid;
531
532        WorldPacket data;
533
534        switch(emote_anim)
535        {
536            case EMOTE_STATE_SLEEP:
537            case EMOTE_STATE_SIT:
538            case EMOTE_STATE_KNEEL:
539            case EMOTE_ONESHOT_NONE:
540                break;
541            default:
542                GetPlayer()->HandleEmoteCommand(emote_anim);
543                break;
544        }
545
546        data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
547        data << GetPlayer()->GetGUID();
548        data << (uint32)text_emote;
549        data << emoteNum;
550        data << (uint32)namlen;
551        if( namlen > 1 )
552        {
553            data.append(nam, namlen);
554        }
555        else
556        {
557            data << (uint8)0x00;
558        }
559
560        GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
561
562        //Send scripted event call
563        if (pCreature && Script)
564            Script->ReceiveEmote(GetPlayer(),pCreature,text_emote);
565    }
566}
567
568void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data )
569{
570    CHECK_PACKET_SIZE(recv_data, 8+1);
571
572    uint64 iguid;
573    uint8 unk;
574    //sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED");
575
576    recv_data >> iguid;
577    recv_data >> unk;                                       // probably related to spam reporting
578
579    Player *player = objmgr.GetPlayer(iguid);
580    if(!player || !player->GetSession())
581        return;
582
583    WorldPacket data;
584    ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(),NULL);
585    player->GetSession()->SendPacket(&data);
586}
Note: See TracBrowser for help on using the browser.