root/trunk/src/game/MiscHandler.cpp @ 233

Revision 233, 51.1 kB (checked in by yumileroy, 17 years ago)

[svn] * Reimplemented packet/update forwarding in more generic way
* Implemented far sight spells (Far Sight, Eagle Eye, etc) at unlimited range and properly forward packets
* Implemented bind vision spells (Mind Vision, etc) to forward packets at unlimited distance
* Implemented Sentry Totem (both vision switching/forwarding and alerting)
* Other misc possession fixes
* Added .bindsight and .unbindsight commands

Please test out the above spells (including Mind Control) and report any issues on the forums.

Original author: gvcoman
Date: 2008-11-14 20:40:35-06:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21#include "Common.h"
22#include "Language.h"
23#include "Database/DatabaseEnv.h"
24#include "Database/DatabaseImpl.h"
25#include "WorldPacket.h"
26#include "Opcodes.h"
27#include "Log.h"
28#include "Player.h"
29#include "World.h"
30#include "ObjectMgr.h"
31#include "WorldSession.h"
32#include "Auth/BigNumber.h"
33#include "Auth/Sha1.h"
34#include "UpdateData.h"
35#include "LootMgr.h"
36#include "Chat.h"
37#include "ScriptCalls.h"
38#include <zlib/zlib.h>
39#include "MapManager.h"
40#include "ObjectAccessor.h"
41#include "Object.h"
42#include "BattleGround.h"
43#include "OutdoorPvP.h"
44#include "SpellAuras.h"
45#include "Pet.h"
46#include "SocialMgr.h"
47
48void WorldSession::HandleRepopRequestOpcode( WorldPacket & /*recv_data*/ )
49{
50    sLog.outDebug( "WORLD: Recvd CMSG_REPOP_REQUEST Message" );
51
52    if(GetPlayer()->isAlive()||GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
53        return;
54
55    // the world update order is sessions, players, creatures
56    // the netcode runs in parallel with all of these
57    // creatures can kill players
58    // so if the server is lagging enough the player can
59    // release spirit after he's killed but before he is updated
60    if(GetPlayer()->getDeathState() == JUST_DIED)
61    {
62        sLog.outDebug("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
63        GetPlayer()->KillPlayer();
64    }
65
66    //this is spirit release confirm?
67    GetPlayer()->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
68    GetPlayer()->BuildPlayerRepop();
69    GetPlayer()->RepopAtGraveyard();
70}
71
72void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
73{
74    CHECK_PACKET_SIZE(recv_data,4+4+1+1+4+4+4+4);
75
76    sLog.outDebug( "WORLD: Recvd CMSG_WHO Message" );
77    //recv_data.hexlike();
78
79    uint32 clientcount = 0;
80
81    uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
82    uint32 zoneids[10];                                     // 10 is client limit
83    std::string player_name, guild_name;
84
85    recv_data >> level_min;                                 // maximal player level, default 0
86    recv_data >> level_max;                                 // minimal player level, default 100
87    recv_data >> player_name;                               // player name, case sensitive...
88
89    // recheck
90    CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+1+4+4+4+4);
91
92    recv_data >> guild_name;                                // guild name, case sensitive...
93
94    // recheck
95    CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+4);
96
97    recv_data >> racemask;                                  // race mask
98    recv_data >> classmask;                                 // class mask
99    recv_data >> zones_count;                               // zones count, client limit=10 (2.0.10)
100
101    if(zones_count > 10)
102        return;                                             // can't be received from real client or broken packet
103
104    // recheck
105    CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4);
106
107    for(uint32 i = 0; i < zones_count; i++)
108    {
109        uint32 temp;
110        recv_data >> temp;                                  // zone id, 0 if zone is unknown...
111        zoneids[i] = temp;
112        sLog.outDebug("Zone %u: %u", i, zoneids[i]);
113    }
114
115    recv_data >> str_count;                                 // user entered strings count, client limit=4 (checked on 2.0.10)
116
117    if(str_count > 4)
118        return;                                             // can't be received from real client or broken packet
119
120    // recheck
121    CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4+(1*str_count));
122
123    sLog.outDebug("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count);
124
125    std::wstring str[4];                                    // 4 is client limit
126    for(uint32 i = 0; i < str_count; i++)
127    {
128        // recheck (have one more byte)
129        CHECK_PACKET_SIZE(recv_data,recv_data.rpos());
130
131        std::string temp;
132        recv_data >> temp;                                  // user entered string, it used as universal search pattern(guild+player name)?
133
134        if(!Utf8toWStr(temp,str[i]))
135            continue;
136
137        wstrToLower(str[i]);
138
139        sLog.outDebug("String %u: %s", i, temp.c_str());
140    }
141
142    std::wstring wplayer_name;
143    std::wstring wguild_name;
144    if(!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
145        return;
146    wstrToLower(wplayer_name);
147    wstrToLower(wguild_name);
148
149    // client send in case not set max level value 100 but mangos support 255 max level,
150    // update it to show GMs with characters after 100 level
151    if(level_max >= 100)
152        level_max = 255;
153
154    uint32 team = _player->GetTeam();
155    uint32 security = GetSecurity();
156    bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
157    bool gmInWhoList         = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
158
159    WorldPacket data( SMSG_WHO, 50 );                       // guess size
160    data << clientcount;                                    // clientcount place holder
161    data << clientcount;                                    // clientcount place holder
162
163    //TODO: Guard Player map
164    HashMapHolder<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();
165    for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
166    {
167        if (security == SEC_PLAYER)
168        {
169            // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
170            if (itr->second->GetTeam() != team && !allowTwoSideWhoList )
171                continue;
172
173            // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
174            if ((itr->second->GetSession()->GetSecurity() > SEC_PLAYER && !gmInWhoList))
175                continue;
176        }
177
178        // check if target is globally visible for player
179        if (!(itr->second->IsVisibleGloballyFor(_player)))
180            continue;
181
182        // check if target's level is in level range
183        uint32 lvl = itr->second->getLevel();
184        if (lvl < level_min || lvl > level_max)
185            continue;
186
187        // check if class matches classmask
188        uint32 class_ = itr->second->getClass();
189        if (!(classmask & (1 << class_)))
190            continue;
191
192        // check if race matches racemask
193        uint32 race = itr->second->getRace();
194        if (!(racemask & (1 << race)))
195            continue;
196
197        uint32 pzoneid = itr->second->GetZoneId();
198
199        bool z_show = true;
200        for(uint32 i = 0; i < zones_count; i++)
201        {
202            if(zoneids[i] == pzoneid)
203            {
204                z_show = true;
205                break;
206            }
207
208            z_show = false;
209        }
210        if (!z_show)
211            continue;
212
213        std::string pname = itr->second->GetName();
214        std::wstring wpname;
215        if(!Utf8toWStr(pname,wpname))
216            continue;
217        wstrToLower(wpname);
218
219        if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
220            continue;
221
222        std::string gname = objmgr.GetGuildNameById(itr->second->GetGuildId());
223        std::wstring wgname;
224        if(!Utf8toWStr(gname,wgname))
225            continue;
226        wstrToLower(wgname);
227
228        if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
229            continue;
230
231        std::string aname;
232        if(AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
233            aname = areaEntry->area_name[GetSessionDbcLocale()];
234
235        bool s_show = true;
236        for(uint32 i = 0; i < str_count; i++)
237        {
238            if (!str[i].empty())
239            {
240                if (wgname.find(str[i]) != std::wstring::npos ||
241                    wpname.find(str[i]) != std::wstring::npos ||
242                    Utf8FitTo(aname, str[i]) )
243                {
244                    s_show = true;
245                    break;
246                }
247                s_show = false;
248            }
249        }
250        if (!s_show)
251            continue;
252
253        data << pname;                                      // player name
254        data << gname;                                      // guild name
255        data << uint32( lvl );                              // player level
256        data << uint32( class_ );                           // player class
257        data << uint32( race );                             // player race
258        data << uint8(0);                                   // new 2.4.0
259        data << uint32( pzoneid );                          // player zone id
260
261        // 49 is maximum player count sent to client - can be overridden
262        // through config, but is unstable
263        if ((++clientcount) == sWorld.getConfig(CONFIG_MAX_WHO))
264            break;
265    }
266
267    data.put( 0,              clientcount );                //insert right count
268    data.put( sizeof(uint32), clientcount );                //insert right count
269
270    SendPacket(&data);
271    sLog.outDebug( "WORLD: Send SMSG_WHO Message" );
272}
273
274void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
275{
276    sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity() );
277
278    if (uint64 lguid = GetPlayer()->GetLootGUID())
279        DoLootRelease(lguid);
280
281    //instant logout for admins, gm's, mod's
282    if( GetSecurity() > SEC_PLAYER )
283    {
284        LogoutPlayer(true);
285        return;
286    }
287
288    //Can not logout if...
289    if( GetPlayer()->isInCombat() ||                        //...is in combat
290        GetPlayer()->duel         ||                        //...is in Duel
291        GetPlayer()->HasAura(9454,0)         ||             //...is frozen by GM via freeze command
292                                                            //...is jumping ...is falling
293        GetPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING))
294    {
295        WorldPacket data( SMSG_LOGOUT_RESPONSE, (2+4) ) ;
296        data << (uint8)0xC;
297        data << uint32(0);
298        data << uint8(0);
299        SendPacket( &data );
300        LogoutRequest(0);
301        return;
302    }
303
304    //instant logout in taverns/cities or on taxi or if its enabled in Trinityd.conf
305    if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || sWorld.getConfig(CONFIG_INSTANT_LOGOUT))
306    {
307        LogoutPlayer(true);
308        return;
309    }
310
311    // not set flags if player can't free move to prevent lost state at logout cancel
312    if(GetPlayer()->CanFreeMove())
313    {
314        GetPlayer()->SetStandState(PLAYER_STATE_SIT);
315
316        WorldPacket data( SMSG_FORCE_MOVE_ROOT, (8+4) );    // guess size
317        data.append(GetPlayer()->GetPackGUID());
318        data << (uint32)2;
319        SendPacket( &data );
320        GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
321    }
322
323    WorldPacket data( SMSG_LOGOUT_RESPONSE, 5 );
324    data << uint32(0);
325    data << uint8(0);
326    SendPacket( &data );
327    LogoutRequest(time(NULL));
328}
329
330void WorldSession::HandlePlayerLogoutOpcode( WorldPacket & /*recv_data*/ )
331{
332    sLog.outDebug( "WORLD: Recvd CMSG_PLAYER_LOGOUT Message" );
333}
334
335void WorldSession::HandleLogoutCancelOpcode( WorldPacket & /*recv_data*/ )
336{
337    sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_CANCEL Message" );
338
339    LogoutRequest(0);
340
341    WorldPacket data( SMSG_LOGOUT_CANCEL_ACK, 0 );
342    SendPacket( &data );
343
344    // not remove flags if can't free move - its not set in Logout request code.
345    if(GetPlayer()->CanFreeMove())
346    {
347        //!we can move again
348        data.Initialize( SMSG_FORCE_MOVE_UNROOT, 8 );       // guess size
349        data.append(GetPlayer()->GetPackGUID());
350        data << uint32(0);
351        SendPacket( &data );
352
353        //! Stand Up
354        GetPlayer()->SetStandState(PLAYER_STATE_NONE);
355
356        //! DISABLE_ROTATE
357        GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
358    }
359
360    sLog.outDebug( "WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message" );
361}
362
363void WorldSession::HandleTogglePvP( WorldPacket & recv_data )
364{
365    // this opcode can be used in two ways: Either set explicit new status or toggle old status
366    if(recv_data.size() == 1)
367    {
368        bool newPvPStatus;
369        recv_data >> newPvPStatus;
370        GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus);
371    }
372    else
373    {
374        GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP);
375    }
376
377    if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
378    {
379        if(!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0)
380            GetPlayer()->UpdatePvP(true, true);
381    }
382    else
383    {
384        if(!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP())
385            GetPlayer()->pvpInfo.endTimer = time(NULL);     // start toggle-off
386    }
387
388    if(OutdoorPvP * pvp = _player->GetOutdoorPvP())
389    {
390        pvp->HandlePlayerActivityChanged(_player);
391    }
392}
393
394void WorldSession::HandleZoneUpdateOpcode( WorldPacket & recv_data )
395{
396    CHECK_PACKET_SIZE(recv_data,4);
397
398    uint32 newZone;
399    recv_data >> newZone;
400
401    sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone);
402
403    GetPlayer()->UpdateZone(newZone);
404
405    GetPlayer()->SendInitWorldStates(true,newZone);
406}
407
408void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data )
409{
410    // When this packet send?
411    CHECK_PACKET_SIZE(recv_data,8);
412
413    uint64 guid ;
414    recv_data >> guid;
415
416    _player->SetUInt32Value(UNIT_FIELD_TARGET,guid);
417
418    // update reputation list if need
419    Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
420    if(!unit)
421        return;
422
423    _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
424}
425
426void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
427{
428    CHECK_PACKET_SIZE(recv_data,8);
429
430    uint64 guid;
431    recv_data >> guid;
432
433    _player->SetSelection(guid);
434
435    // update reputation list if need
436    Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
437    if(!unit)
438        return;
439
440    _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
441}
442
443void WorldSession::HandleStandStateChangeOpcode( WorldPacket & recv_data )
444{
445    CHECK_PACKET_SIZE(recv_data,1);
446
447    sLog.outDebug( "WORLD: Received CMSG_STAND_STATE_CHANGE"  );
448    uint8 animstate;
449    recv_data >> animstate;
450
451    _player->SetStandState(animstate);
452}
453
454void WorldSession::HandleFriendListOpcode( WorldPacket & recv_data )
455{
456    CHECK_PACKET_SIZE(recv_data, 4);
457    sLog.outDebug( "WORLD: Received CMSG_CONTACT_LIST" );
458    uint32 unk;
459    recv_data >> unk;
460    sLog.outDebug("unk value is %u", unk);
461    _player->GetSocial()->SendSocialList();
462}
463
464void WorldSession::HandleAddFriendOpcode( WorldPacket & recv_data )
465{
466    CHECK_PACKET_SIZE(recv_data, 1+1);
467
468    sLog.outDebug( "WORLD: Received CMSG_ADD_FRIEND" );
469
470    std::string friendName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN);
471    std::string friendNote;
472
473    recv_data >> friendName;
474
475    // recheck
476    CHECK_PACKET_SIZE(recv_data, (friendName.size()+1)+1);
477
478    recv_data >> friendNote;
479
480    if(!normalizePlayerName(friendName))
481        return;
482
483    CharacterDatabase.escape_string(friendName);            // prevent SQL injection - normal name don't must changed by this call
484
485    sLog.outDebug( "WORLD: %s asked to add friend : '%s'",
486        GetPlayer()->GetName(), friendName.c_str() );
487
488    CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race FROM characters WHERE name = '%s'", friendName.c_str());
489}
490
491void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult *result, uint32 accountId, std::string friendNote)
492{
493    if(!result)
494        return;
495
496    uint64 friendGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
497    uint32 team = Player::TeamForRace((*result)[1].GetUInt8());
498
499    delete result;
500
501    WorldSession * session = sWorld.FindSession(accountId);
502    if(!session || !session->GetPlayer())
503        return;
504
505    FriendsResult friendResult = FRIEND_NOT_FOUND;
506    if(friendGuid)
507    {
508        if(friendGuid==session->GetPlayer()->GetGUID())
509            friendResult = FRIEND_SELF;
510        else if(session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR)
511            friendResult = FRIEND_ENEMY;
512        else if(session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
513            friendResult = FRIEND_ALREADY;
514        else
515        {
516            Player* pFriend = ObjectAccessor::FindPlayer(friendGuid);
517            if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer()))
518                friendResult = FRIEND_ADDED_ONLINE;
519            else
520                friendResult = FRIEND_ADDED_OFFLINE;
521
522            if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
523            {
524                friendResult = FRIEND_LIST_FULL;
525                sLog.outDebug( "WORLD: %s's friend list is full.", session->GetPlayer()->GetName());
526            }
527
528            session->GetPlayer()->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote);
529        }
530    }
531
532    sSocialMgr.SendFriendStatus(session->GetPlayer(), friendResult, GUID_LOPART(friendGuid), false);
533
534    sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
535}
536
537void WorldSession::HandleDelFriendOpcode( WorldPacket & recv_data )
538{
539    CHECK_PACKET_SIZE(recv_data, 8);
540
541    uint64 FriendGUID;
542
543    sLog.outDebug( "WORLD: Received CMSG_DEL_FRIEND" );
544
545    recv_data >> FriendGUID;
546
547    _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false);
548
549    sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), false);
550
551    sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
552}
553
554void WorldSession::HandleAddIgnoreOpcode( WorldPacket & recv_data )
555{
556    CHECK_PACKET_SIZE(recv_data,1);
557
558    sLog.outDebug( "WORLD: Received CMSG_ADD_IGNORE" );
559
560    std::string IgnoreName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN);
561
562    recv_data >> IgnoreName;
563
564    if(!normalizePlayerName(IgnoreName))
565        return;
566
567    CharacterDatabase.escape_string(IgnoreName);            // prevent SQL injection - normal name don't must changed by this call
568
569    sLog.outDebug( "WORLD: %s asked to Ignore: '%s'",
570        GetPlayer()->GetName(), IgnoreName.c_str() );
571
572    CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddIgnoreOpcodeCallBack, GetAccountId(), "SELECT guid FROM characters WHERE name = '%s'", IgnoreName.c_str());
573}
574
575void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult *result, uint32 accountId)
576{
577    if(!result)
578        return;
579
580    uint64 IgnoreGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
581
582    delete result;
583
584    WorldSession * session = sWorld.FindSession(accountId);
585    if(!session || !session->GetPlayer())
586        return;
587
588    FriendsResult ignoreResult = FRIEND_IGNORE_NOT_FOUND;
589    if(IgnoreGuid)
590    {
591        if(IgnoreGuid==session->GetPlayer()->GetGUID())              //not add yourself
592            ignoreResult = FRIEND_IGNORE_SELF;
593        else if( session->GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid)) )
594            ignoreResult = FRIEND_IGNORE_ALREADY;
595        else
596        {
597            ignoreResult = FRIEND_IGNORE_ADDED;
598
599            // ignore list full
600            if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true))
601                ignoreResult = FRIEND_IGNORE_FULL;
602        }
603    }
604
605    sSocialMgr.SendFriendStatus(session->GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), false);
606
607    sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
608}
609
610void WorldSession::HandleDelIgnoreOpcode( WorldPacket & recv_data )
611{
612    CHECK_PACKET_SIZE(recv_data, 8);
613
614    uint64 IgnoreGUID;
615
616    sLog.outDebug( "WORLD: Received CMSG_DEL_IGNORE" );
617
618    recv_data >> IgnoreGUID;
619
620    _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true);
621
622    sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), false);
623
624    sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
625}
626
627void WorldSession::HandleSetFriendNoteOpcode( WorldPacket & recv_data )
628{
629    CHECK_PACKET_SIZE(recv_data, 8+1);
630    uint64 guid;
631    std::string note;
632    recv_data >> guid >> note;
633    _player->GetSocial()->SetFriendNote(guid, note);
634}
635
636void WorldSession::HandleBugOpcode( WorldPacket & recv_data )
637{
638    CHECK_PACKET_SIZE(recv_data,4+4+1+4+1);
639
640    uint32 suggestion, contentlen;
641    std::string content;
642    uint32 typelen;
643    std::string type;
644
645    recv_data >> suggestion >> contentlen >> content;
646
647    //recheck
648    CHECK_PACKET_SIZE(recv_data,4+4+(content.size()+1)+4+1);
649
650    recv_data >> typelen >> type;
651
652    if( suggestion == 0 )
653        sLog.outDebug( "WORLD: Received CMSG_BUG [Bug Report]" );
654    else
655        sLog.outDebug( "WORLD: Received CMSG_BUG [Suggestion]" );
656
657    sLog.outDebug( type.c_str( ) );
658    sLog.outDebug( content.c_str( ) );
659
660    CharacterDatabase.escape_string(type);
661    CharacterDatabase.escape_string(content);
662    CharacterDatabase.PExecute ("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type.c_str( ), content.c_str( ));
663}
664
665void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data)
666{
667    CHECK_PACKET_SIZE(recv_data,8);
668
669    sLog.outDetail("WORLD: Received CMSG_RECLAIM_CORPSE");
670    if (GetPlayer()->isAlive())
671        return;
672
673    if (BattleGround * bg = _player->GetBattleGround())
674        if(bg->isArena())
675            return;
676
677    // body not released yet
678    if(!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
679        return;
680
681    Corpse *corpse = GetPlayer()->GetCorpse();
682
683    if (!corpse )
684        return;
685
686    // prevent resurrect before 30-sec delay after body release not finished
687    if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL))
688        return;
689
690    float dist = corpse->GetDistance2d(GetPlayer());
691    sLog.outDebug("Corpse 2D Distance: \t%f",dist);
692    if (dist > CORPSE_RECLAIM_RADIUS)
693        return;
694
695    uint64 guid;
696    recv_data >> guid;
697
698    // resurrect
699    GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f : 0.5f);
700
701    // spawn bones
702    GetPlayer()->SpawnCorpseBones();
703
704    GetPlayer()->SaveToDB();
705}
706
707void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data)
708{
709    CHECK_PACKET_SIZE(recv_data,8+1);
710
711    sLog.outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE");
712
713    if(GetPlayer()->isAlive())
714        return;
715
716    uint64 guid;
717    uint8 status;
718    recv_data >> guid;
719    recv_data >> status;
720
721    if(status == 0)
722    {
723        GetPlayer()->clearResurrectRequestData();           // reject
724        return;
725    }
726
727    if(!GetPlayer()->isRessurectRequestedBy(guid))
728        return;
729
730    GetPlayer()->ResurectUsingRequestData();
731    GetPlayer()->SaveToDB();
732}
733
734void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
735{
736    CHECK_PACKET_SIZE(recv_data,4);
737
738    sLog.outDebug("WORLD: Received CMSG_AREATRIGGER");
739
740    uint32 Trigger_ID;
741
742    recv_data >> Trigger_ID;
743    sLog.outDebug("Trigger ID:%u",Trigger_ID);
744
745    if(GetPlayer()->isInFlight())
746    {
747        sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
748        return;
749    }
750
751    AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
752    if(!atEntry)
753    {
754        sLog.outDebug("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
755        return;
756    }
757
758    if (GetPlayer()->GetMapId()!=atEntry->mapid)
759    {
760        sLog.outDebug("Player '%s' (GUID: %u) too far (trigger map: %u player map: %u), ignore Area Trigger ID: %u", GetPlayer()->GetName(), atEntry->mapid, GetPlayer()->GetMapId(), GetPlayer()->GetGUIDLow(), Trigger_ID);
761        return;
762    }
763
764    // delta is safe radius
765    const float delta = 5.0f;
766    // check if player in the range of areatrigger
767    Player* pl = GetPlayer();
768
769    if (atEntry->radius > 0)
770    {
771        // if we have radius check it
772        float dist = pl->GetDistance(atEntry->x,atEntry->y,atEntry->z);
773        if(dist > atEntry->radius + delta)
774        {
775            sLog.outDebug("Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u",
776                pl->GetName(), pl->GetGUIDLow(), atEntry->radius, dist, Trigger_ID);
777            return;
778        }
779    }
780    else
781    {
782        // we have only extent
783        float dx = pl->GetPositionX() - atEntry->x;
784        float dy = pl->GetPositionY() - atEntry->y;
785        float dz = pl->GetPositionZ() - atEntry->z;
786        double es = sin(atEntry->box_orientation);
787        double ec = cos(atEntry->box_orientation);
788        // calc rotated vector based on extent axis
789        double rotateDx = dx*ec - dy*es;
790        double rotateDy = dx*es + dy*ec;
791
792        if( (fabs(rotateDx) > atEntry->box_x/2 + delta) ||
793            (fabs(rotateDy) > atEntry->box_y/2 + delta) ||
794            (fabs(dz) > atEntry->box_z/2 + delta) )
795        {
796            sLog.outDebug("Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %f 1/2 box Z: %f rotate dX: %f rotate dY: %f dZ:%f), ignore Area Trigger ID: %u",
797                pl->GetName(), pl->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotateDx, rotateDy, dz, Trigger_ID);
798            return;
799        }
800    }
801
802    if(Script->scriptAreaTrigger(GetPlayer(), atEntry))
803        return;
804
805    uint32 quest_id = objmgr.GetQuestForAreaTrigger( Trigger_ID );
806    if( quest_id && GetPlayer()->isAlive() && GetPlayer()->IsActiveQuest(quest_id) )
807    {
808        Quest const* pQuest = objmgr.GetQuestTemplate(quest_id);
809        if( pQuest )
810        {
811            if(GetPlayer()->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE)
812                GetPlayer()->AreaExploredOrEventHappens( quest_id );
813        }
814    }
815
816    if(objmgr.IsTavernAreaTrigger(Trigger_ID))
817    {
818        // set resting flag we are in the inn
819        GetPlayer()->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
820        GetPlayer()->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z);
821        GetPlayer()->SetRestType(REST_TYPE_IN_TAVERN);
822
823        if(sWorld.IsFFAPvPRealm())
824            GetPlayer()->RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
825
826        return;
827    }
828
829    if(GetPlayer()->InBattleGround())
830    {
831        BattleGround* bg = GetPlayer()->GetBattleGround();
832        if(bg)
833            if(bg->GetStatus() == STATUS_IN_PROGRESS)
834                bg->HandleAreaTrigger(GetPlayer(), Trigger_ID);
835
836        return;
837    }
838
839    if(OutdoorPvP * pvp = GetPlayer()->GetOutdoorPvP())
840    {
841        if(pvp->HandleAreaTrigger(_player, Trigger_ID))
842            return;
843    }
844
845    // NULL if all values default (non teleport trigger)
846    AreaTrigger const* at = objmgr.GetAreaTrigger(Trigger_ID);
847    if(!at)
848        return;
849
850    if(!GetPlayer()->isGameMaster())
851    {
852        uint32 missingLevel = 0;
853        if(GetPlayer()->getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
854            missingLevel = at->requiredLevel;
855
856        // must have one or the other, report the first one that's missing
857        uint32 missingItem = 0;
858        if(at->requiredItem)
859        {
860            if(!GetPlayer()->HasItemCount(at->requiredItem, 1) &&
861                (!at->requiredItem2 || !GetPlayer()->HasItemCount(at->requiredItem2, 1)))
862                missingItem = at->requiredItem;
863        }
864        else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1))
865            missingItem = at->requiredItem2;
866
867        uint32 missingKey = 0;
868        if(GetPlayer()->GetDifficulty() == DIFFICULTY_HEROIC)
869        {
870            if(at->heroicKey)
871            {
872                if(!GetPlayer()->HasItemCount(at->heroicKey, 1) &&
873                    (!at->heroicKey2 || !GetPlayer()->HasItemCount(at->heroicKey2, 1)))
874                    missingKey = at->heroicKey;
875            }
876            else if(at->heroicKey2 && !GetPlayer()->HasItemCount(at->heroicKey2, 1))
877                missingKey = at->heroicKey2;
878        }
879
880        uint32 missingQuest = 0;
881        if(at->requiredQuest && !GetPlayer()->GetQuestRewardStatus(at->requiredQuest))
882            missingQuest = at->requiredQuest;
883
884        if(missingLevel || missingItem || missingKey || missingQuest)
885        {
886            // TODO: all this is probably wrong
887            if(missingItem)
888                SendAreaTriggerMessage(GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1);
889            else if(missingKey)
890                GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY2);
891            else if(missingQuest)
892                SendAreaTriggerMessage(at->requiredFailedText.c_str());
893            else if(missingLevel)
894                SendAreaTriggerMessage(GetTrinityString(LANG_LEVEL_MINREQUIRED), missingLevel);
895            return;
896        }
897    }
898
899    GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,TELE_TO_NOT_LEAVE_TRANSPORT);
900}
901
902void WorldSession::HandleUpdateAccountData(WorldPacket &/*recv_data*/)
903{
904    sLog.outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA");
905    //recv_data.hexlike();
906}
907
908void WorldSession::HandleRequestAccountData(WorldPacket& /*recv_data*/)
909{
910    sLog.outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA");
911    //recv_data.hexlike();
912}
913
914void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
915{
916    CHECK_PACKET_SIZE(recv_data,1+2+1+1);
917
918    sLog.outDebug(  "WORLD: Received CMSG_SET_ACTION_BUTTON" );
919    uint8 button, misc, type;
920    uint16 action;
921    recv_data >> button >> action >> misc >> type;
922    sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u MISC: %u", button, action, type, misc );
923    if(action==0)
924    {
925        sLog.outDetail( "MISC: Remove action from button %u", button );
926
927        GetPlayer()->removeActionButton(button);
928    }
929    else
930    {
931        if(type==ACTION_BUTTON_MACRO || type==ACTION_BUTTON_CMACRO)
932        {
933            sLog.outDetail( "MISC: Added Macro %u into button %u", action, button );
934            GetPlayer()->addActionButton(button,action,type,misc);
935        }
936        else if(type==ACTION_BUTTON_SPELL)
937        {
938            sLog.outDetail( "MISC: Added Action %u into button %u", action, button );
939            GetPlayer()->addActionButton(button,action,type,misc);
940        }
941        else if(type==ACTION_BUTTON_ITEM)
942        {
943            sLog.outDetail( "MISC: Added Item %u into button %u", action, button );
944            GetPlayer()->addActionButton(button,action,type,misc);
945        }
946        else
947            sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button );
948    }
949}
950
951void WorldSession::HandleCompleteCinema( WorldPacket & /*recv_data*/ )
952{
953    DEBUG_LOG( "WORLD: Player is watching cinema" );
954}
955
956void WorldSession::HandleNextCinematicCamera( WorldPacket & /*recv_data*/ )
957{
958    DEBUG_LOG( "WORLD: Which movie to play" );
959}
960
961void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & /*recv_data*/ )
962{
963    /*  WorldSession::Update( getMSTime() );*/
964    DEBUG_LOG( "WORLD: Time Lag/Synchronization Resent/Update" );
965
966    /*
967        CHECK_PACKET_SIZE(recv_data,8+4);
968        uint64 guid;
969        uint32 time_skipped;
970        recv_data >> guid;
971        recv_data >> time_skipped;
972        sLog.outDebug( "WORLD: CMSG_MOVE_TIME_SKIPPED" );
973
974        /// TODO
975        must be need use in Trinity
976        We substract server Lags to move time ( AntiLags )
977        for exmaple
978        GetPlayer()->ModifyLastMoveTime( -int32(time_skipped) );
979    */
980}
981
982void WorldSession::HandleFeatherFallAck(WorldPacket &/*recv_data*/)
983{
984    DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
985}
986
987void WorldSession::HandleMoveUnRootAck(WorldPacket&/* recv_data*/)
988{
989    /*
990        CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
991
992        sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK" );
993        recv_data.hexlike();
994        uint64 guid;
995        uint64 unknown1;
996        uint32 unknown2;
997        float PositionX;
998        float PositionY;
999        float PositionZ;
1000        float Orientation;
1001
1002        recv_data >> guid;
1003        recv_data >> unknown1;
1004        recv_data >> unknown2;
1005        recv_data >> PositionX;
1006        recv_data >> PositionY;
1007        recv_data >> PositionZ;
1008        recv_data >> Orientation;
1009
1010        // TODO for later may be we can use for anticheat
1011        DEBUG_LOG("Guid " I64FMTD,guid);
1012        DEBUG_LOG("unknown1 " I64FMTD,unknown1);
1013        DEBUG_LOG("unknown2 %u",unknown2);
1014        DEBUG_LOG("X %f",PositionX);
1015        DEBUG_LOG("Y %f",PositionY);
1016        DEBUG_LOG("Z %f",PositionZ);
1017        DEBUG_LOG("O %f",Orientation);
1018    */
1019}
1020
1021void WorldSession::HandleMoveRootAck(WorldPacket&/* recv_data*/)
1022{
1023    /*
1024        CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
1025
1026        sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_ROOT_ACK" );
1027        recv_data.hexlike();
1028        uint64 guid;
1029        uint64 unknown1;
1030        uint32 unknown2;
1031        float PositionX;
1032        float PositionY;
1033        float PositionZ;
1034        float Orientation;
1035
1036        recv_data >> guid;
1037        recv_data >> unknown1;
1038        recv_data >> unknown2;
1039        recv_data >> PositionX;
1040        recv_data >> PositionY;
1041        recv_data >> PositionZ;
1042        recv_data >> Orientation;
1043
1044        // for later may be we can use for anticheat
1045        DEBUG_LOG("Guid " I64FMTD,guid);
1046        DEBUG_LOG("unknown1 " I64FMTD,unknown1);
1047        DEBUG_LOG("unknown1 %u",unknown2);
1048        DEBUG_LOG("X %f",PositionX);
1049        DEBUG_LOG("Y %f",PositionY);
1050        DEBUG_LOG("Z %f",PositionZ);
1051        DEBUG_LOG("O %f",Orientation);
1052    */
1053}
1054
1055void WorldSession::HandleMoveTeleportAck(WorldPacket&/* recv_data*/)
1056{
1057    /*
1058        CHECK_PACKET_SIZE(recv_data,8+4);
1059
1060        sLog.outDebug("MSG_MOVE_TELEPORT_ACK");
1061        uint64 guid;
1062        uint32 flags, time;
1063
1064        recv_data >> guid;
1065        recv_data >> flags >> time;
1066        DEBUG_LOG("Guid " I64FMTD,guid);
1067        DEBUG_LOG("Flags %u, time %u",flags, time/1000);
1068    */
1069}
1070
1071void WorldSession::HandleSetActionBar(WorldPacket& recv_data)
1072{
1073    CHECK_PACKET_SIZE(recv_data,1);
1074
1075    uint8 ActionBar;
1076
1077    recv_data >> ActionBar;
1078
1079    if(!GetPlayer())                                        // ignore until not logged (check needed because STATUS_AUTHED)
1080    {
1081        if(ActionBar!=0)
1082            sLog.outError("WorldSession::HandleSetActionBar in not logged state with value: %u, ignored",uint32(ActionBar));
1083        return;
1084    }
1085
1086    GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar);
1087}
1088
1089void WorldSession::HandleWardenDataOpcode(WorldPacket& /*recv_data*/)
1090{
1091    /*
1092        CHECK_PACKET_SIZE(recv_data,1);
1093
1094        uint8 tmp;
1095        recv_data >> tmp;
1096        sLog.outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u",tmp);
1097    */
1098}
1099
1100void WorldSession::HandlePlayedTime(WorldPacket& /*recv_data*/)
1101{
1102    uint32 TotalTimePlayed = GetPlayer()->GetTotalPlayedTime();
1103    uint32 LevelPlayedTime = GetPlayer()->GetLevelPlayedTime();
1104
1105    WorldPacket data(SMSG_PLAYED_TIME, 8);
1106    data << TotalTimePlayed;
1107    data << LevelPlayedTime;
1108    SendPacket(&data);
1109}
1110
1111void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
1112{
1113    CHECK_PACKET_SIZE(recv_data, 8);
1114
1115    uint64 guid;
1116    recv_data >> guid;
1117    DEBUG_LOG("Inspected guid is " I64FMTD, guid);
1118
1119    _player->SetSelection(guid);
1120
1121    Player *plr = objmgr.GetPlayer(guid);
1122    if(!plr)                                                // wrong player
1123        return;
1124
1125    uint32 talent_points = 0x3D;
1126    uint32 guid_size = plr->GetPackGUID().size();
1127    WorldPacket data(SMSG_INSPECT_TALENT, 4+talent_points);
1128    data.append(plr->GetPackGUID());
1129    data << uint32(talent_points);
1130
1131    // fill by 0 talents array
1132    for(uint32 i = 0; i < talent_points; ++i)
1133        data << uint8(0);
1134
1135    if(sWorld.getConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster())
1136    {
1137        // find class talent tabs (all players have 3 talent tabs)
1138        uint32 const* talentTabIds = GetTalentTabPages(plr->getClass());
1139
1140        uint32 talentTabPos = 0;                            // pos of first talent rank in tab including all prev tabs
1141        for(uint32 i = 0; i < 3; ++i)
1142        {
1143            uint32 talentTabId = talentTabIds[i];
1144
1145            // fill by real data
1146            for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
1147            {
1148                TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
1149                if(!talentInfo)
1150                    continue;
1151
1152                // skip another tab talents
1153                if(talentInfo->TalentTab != talentTabId)
1154                    continue;
1155
1156                // find talent rank
1157                uint32 curtalent_maxrank = 0;
1158                for(uint32 k = 5; k > 0; --k)
1159                {
1160                    if(talentInfo->RankID[k-1] && plr->HasSpell(talentInfo->RankID[k-1]))
1161                    {
1162                        curtalent_maxrank = k;
1163                        break;
1164                    }
1165                }
1166
1167                // not learned talent
1168                if(!curtalent_maxrank)
1169                    continue;
1170
1171                // 1 rank talent bit index
1172                uint32 curtalent_index = talentTabPos + GetTalentInspectBitPosInTab(talentId);
1173
1174                uint32 curtalent_rank_index = curtalent_index+curtalent_maxrank-1;
1175
1176                // slot/offset in 7-bit bytes
1177                uint32 curtalent_rank_slot7   = curtalent_rank_index / 7;
1178                uint32 curtalent_rank_offset7 = curtalent_rank_index % 7;
1179
1180                // rank pos with skipped 8 bit
1181                uint32 curtalent_rank_index2 = curtalent_rank_slot7 * 8 + curtalent_rank_offset7;
1182
1183                // slot/offset in 8-bit bytes with skipped high bit
1184                uint32 curtalent_rank_slot = curtalent_rank_index2 / 8;
1185                uint32 curtalent_rank_offset =  curtalent_rank_index2 % 8;
1186
1187                // apply mask
1188                uint32 val = data.read<uint8>(guid_size + 4 + curtalent_rank_slot);
1189                val |= (1 << curtalent_rank_offset);
1190                data.put<uint8>(guid_size + 4 + curtalent_rank_slot, val & 0xFF);
1191            }
1192
1193            talentTabPos += GetTalentTabInspectBitSize(talentTabId);
1194        }
1195    }
1196
1197    SendPacket(&data);
1198}
1199
1200void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data)
1201{
1202    CHECK_PACKET_SIZE(recv_data, 8);
1203
1204    uint64 guid;
1205    recv_data >> guid;
1206
1207    Player *player = objmgr.GetPlayer(guid);
1208
1209    if(!player)
1210    {
1211        sLog.outError("InspectHonorStats: WTF, player not found...");
1212        return;
1213    }
1214
1215    WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4);
1216    data << uint64(player->GetGUID());
1217    data << uint8(player->GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY));
1218    data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS));
1219    data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION));
1220    data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION));
1221    data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS));
1222    SendPacket(&data);
1223}
1224
1225void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data)
1226{
1227    CHECK_PACKET_SIZE(recv_data,4+4+4+4+4+4);
1228
1229    // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180
1230    // Received opcode CMSG_WORLD_TELEPORT
1231    // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593
1232
1233    //sLog.outDebug("Received opcode CMSG_WORLD_TELEPORT");
1234
1235    if(GetPlayer()->isInFlight())
1236    {
1237        sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore worldport command.",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow());
1238        return;
1239    }
1240
1241    uint32 time;
1242    uint32 mapid;
1243    float PositionX;
1244    float PositionY;
1245    float PositionZ;
1246    float Orientation;
1247
1248    recv_data >> time;                                      // time in m.sec.
1249    recv_data >> mapid;
1250    recv_data >> PositionX;
1251    recv_data >> PositionY;
1252    recv_data >> PositionZ;
1253    recv_data >> Orientation;                               // o (3.141593 = 180 degrees)
1254    DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation);
1255
1256    if (GetSecurity() >= SEC_ADMINISTRATOR)
1257        GetPlayer()->TeleportTo(mapid,PositionX,PositionY,PositionZ,Orientation);
1258    else
1259        SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
1260    sLog.outDebug("Received worldport command from player %s", GetPlayer()->GetName());
1261}
1262
1263void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
1264{
1265    CHECK_PACKET_SIZE(recv_data, 1);
1266
1267    sLog.outDebug("Received opcode CMSG_WHOIS");
1268    std::string charname;
1269    recv_data >> charname;
1270
1271    if (GetSecurity() < SEC_ADMINISTRATOR)
1272    {
1273        SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
1274        return;
1275    }
1276
1277    if(charname.empty())
1278    {
1279        SendNotification(LANG_NEED_CHARACTER_NAME);
1280        return;
1281    }
1282
1283    normalizePlayerName (charname);
1284
1285    Player *plr = objmgr.GetPlayer(charname.c_str());
1286
1287    if(!plr)
1288    {
1289        SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str());
1290        return;
1291    }
1292
1293    uint32 accid = plr->GetSession()->GetAccountId();
1294
1295    QueryResult *result = loginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
1296    if(!result)
1297    {
1298        SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str());
1299        return;
1300    }
1301
1302    Field *fields = result->Fetch();
1303    std::string acc = fields[0].GetCppString();
1304    if(acc.empty())
1305        acc = "Unknown";
1306    std::string email = fields[1].GetCppString();
1307    if(email.empty())
1308        email = "Unknown";
1309    std::string lastip = fields[2].GetCppString();
1310    if(lastip.empty())
1311        lastip = "Unknown";
1312
1313    std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip;
1314
1315    WorldPacket data(SMSG_WHOIS, msg.size()+1);
1316    data << msg;
1317    _player->GetSession()->SendPacket(&data);
1318
1319    delete result;
1320
1321    sLog.outDebug("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str());
1322}
1323
1324void WorldSession::HandleReportSpamOpcode( WorldPacket & recv_data )
1325{
1326    CHECK_PACKET_SIZE(recv_data, 1+8);
1327    sLog.outDebug("WORLD: CMSG_REPORT_SPAM");
1328    recv_data.hexlike();
1329
1330    uint8 spam_type;                                        // 0 - mail, 1 - chat
1331    uint64 spammer_guid;
1332    uint32 unk1, unk2, unk3, unk4 = 0;
1333    std::string description = "";
1334    recv_data >> spam_type;                                 // unk 0x01 const, may be spam type (mail/chat)
1335    recv_data >> spammer_guid;                              // player guid
1336    switch(spam_type)
1337    {
1338        case 0:
1339            CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4);
1340            recv_data >> unk1;                              // const 0
1341            recv_data >> unk2;                              // probably mail id
1342            recv_data >> unk3;                              // const 0
1343            break;
1344        case 1:
1345            CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4+4+1);
1346            recv_data >> unk1;                              // probably language
1347            recv_data >> unk2;                              // message type?
1348            recv_data >> unk3;                              // probably channel id
1349            recv_data >> unk4;                              // unk random value
1350            recv_data >> description;                       // spam description string (messagetype, channel name, player name, message)
1351            break;
1352    }
1353
1354    // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam.
1355    // if it's mail spam - ALL mails from this spammer automatically removed by client
1356
1357    // Complaint Received message
1358    WorldPacket data(SMSG_COMPLAIN_RESULT, 1);
1359    data << uint8(0);
1360    SendPacket(&data);
1361
1362    sLog.outDebug("REPORT SPAM: type %u, guid %u, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, GUID_LOPART(spammer_guid), unk1, unk2, unk3, unk4, description.c_str());
1363}
1364
1365void WorldSession::HandleRealmStateRequestOpcode( WorldPacket & recv_data )
1366{
1367    CHECK_PACKET_SIZE(recv_data, 4);
1368
1369    sLog.outDebug("CMSG_REALM_SPLIT");
1370
1371    uint32 unk;
1372    std::string split_date = "01/01/01";
1373    recv_data >> unk;
1374
1375    WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1);
1376    data << unk;
1377    data << uint32(0x00000000);                             // realm split state
1378    // split states:
1379    // 0x0 realm normal
1380    // 0x1 realm split
1381    // 0x2 realm split pending
1382    data << split_date;
1383    SendPacket(&data);
1384    //sLog.outDebug("response sent %u", unk);
1385}
1386
1387void WorldSession::HandleFarSightOpcode( WorldPacket & recv_data )
1388{
1389    CHECK_PACKET_SIZE(recv_data, 1);
1390
1391    sLog.outDebug("WORLD: CMSG_FAR_SIGHT");
1392    //recv_data.hexlike();
1393
1394    uint8 apply;
1395    recv_data >> apply;
1396
1397    CellPair pair;
1398
1399    switch(apply)
1400    {
1401        case 0:
1402            _player->SetFarsightVision(false);
1403            pair = Trinity::ComputeCellPair(_player->GetPositionX(), _player->GetPositionY());
1404            sLog.outDebug("Player %u set vision to himself", _player->GetGUIDLow());
1405            break;
1406        case 1:
1407            _player->SetFarsightVision(true);
1408            if (WorldObject* obj = _player->GetFarsightTarget())
1409                pair = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
1410            else
1411                return;
1412            sLog.outDebug("Player %u set vision to farsight target " I64FMTD ".", _player->GetGUIDLow(), _player->GetUInt64Value(PLAYER_FARSIGHT));
1413            break;
1414        default:
1415            sLog.outDebug("Unhandled mode in CMSG_FAR_SIGHT: %u", apply);
1416            return;
1417    }
1418    // Update visibility after vision change
1419    Cell cell(pair);
1420    GetPlayer()->GetMap()->UpdateObjectsVisibilityFor(_player, cell, pair);
1421}
1422
1423void WorldSession::HandleChooseTitleOpcode( WorldPacket & recv_data )
1424{
1425    CHECK_PACKET_SIZE(recv_data, 4);
1426
1427    sLog.outDebug("CMSG_SET_TITLE");
1428
1429    int32 title;
1430    recv_data >> title;
1431
1432    // -1 at none
1433    if(title > 0 && title < 64)
1434    {
1435       if(!GetPlayer()->HasFlag64(PLAYER__FIELD_KNOWN_TITLES,uint64(1) << title))
1436            return;
1437    }
1438    else
1439        title = 0;
1440
1441    GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title);
1442}
1443
1444void WorldSession::HandleAllowMoveAckOpcode( WorldPacket & recv_data )
1445{
1446    CHECK_PACKET_SIZE(recv_data, 4+4);
1447
1448    sLog.outDebug("CMSG_ALLOW_MOVE_ACK");
1449
1450    uint32 counter, time_;
1451    recv_data >> counter >> time_;
1452
1453    // time_ seems always more than getMSTime()
1454    uint32 diff = getMSTimeDiff(getMSTime(),time_);
1455
1456    sLog.outDebug("response sent: counter %u, time %u (HEX: %X), ms. time %u, diff %u", counter, time_, time_, getMSTime(), diff);
1457}
1458
1459void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ )
1460{
1461    sLog.outDebug("WORLD: CMSG_RESET_INSTANCES");
1462    Group *pGroup = _player->GetGroup();
1463    if(pGroup)
1464    {
1465        if(pGroup->IsLeader(_player->GetGUID()))
1466            pGroup->ResetInstances(INSTANCE_RESET_ALL, _player);
1467    }
1468    else
1469        _player->ResetInstances(INSTANCE_RESET_ALL);
1470}
1471
1472void WorldSession::HandleDungeonDifficultyOpcode( WorldPacket & recv_data )
1473{
1474    CHECK_PACKET_SIZE(recv_data, 4);
1475
1476    sLog.outDebug("MSG_SET_DUNGEON_DIFFICULTY");
1477
1478    uint32 mode;
1479    recv_data >> mode;
1480
1481    if(mode == _player->GetDifficulty())
1482        return;
1483
1484    if(mode > DIFFICULTY_HEROIC)
1485    {
1486        sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
1487        return;
1488    }
1489
1490    // cannot reset while in an instance
1491    Map *map = _player->GetMap();
1492    if(map && map->IsDungeon())
1493    {
1494        sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow());
1495        return;
1496    }
1497
1498    if(_player->getLevel() < LEVELREQUIREMENT_HEROIC)
1499        return;
1500    Group *pGroup = _player->GetGroup();
1501    if(pGroup)
1502    {
1503        if(pGroup->IsLeader(_player->GetGUID()))
1504        {
1505            // the difficulty is set even if the instances can't be reset
1506            //_player->SendDungeonDifficulty(true);
1507            pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player);
1508            pGroup->SetDifficulty(mode);
1509        }
1510    }
1511    else
1512    {
1513        _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY);
1514        _player->SetDifficulty(mode);
1515    }
1516}
1517
1518void WorldSession::HandleNewUnknownOpcode( WorldPacket & recv_data )
1519{
1520    sLog.outDebug("New Unknown Opcode %u", recv_data.GetOpcode());
1521    recv_data.hexlike();
1522    /*
1523    New Unknown Opcode 837
1524    STORAGE_SIZE: 60
1525    02 00 00 00 00 00 00 00 | 00 00 00 00 01 20 00 00
1526    89 EB 33 01 71 5C 24 C4 | 15 03 35 45 74 47 8B 42
1527    BA B8 1B 40 00 00 00 00 | 00 00 00 00 77 66 42 BF
1528    23 91 26 3F 00 00 60 41 | 00 00 00 00
1529
1530    New Unknown Opcode 837
1531    STORAGE_SIZE: 44
1532    02 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
1533    7B 80 34 01 84 EA 2B C4 | 5F A1 36 45 C9 39 1C 42
1534    BA B8 1B 40 CE 06 00 00 | 00 00 80 3F
1535    */
1536}
1537
1538void WorldSession::HandleDismountOpcode( WorldPacket & /*recv_data*/ )
1539{
1540    sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA");
1541    //recv_data.hexlike();
1542
1543    //If player is not mounted, so go out :)
1544    if (!_player->IsMounted())                              // not blizz like; no any messages on blizz
1545    {
1546        ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED);
1547        return;
1548    }
1549
1550    if(_player->isInFlight())                               // not blizz like; no any messages on blizz
1551    {
1552        ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT);
1553        return;
1554    }
1555
1556    _player->Unmount();
1557    _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
1558}
1559
1560void WorldSession::HandleMoveFlyModeChangeAckOpcode( WorldPacket & recv_data )
1561{
1562    CHECK_PACKET_SIZE(recv_data, 8+4+4);
1563
1564    // fly mode on/off
1565    sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
1566    //recv_data.hexlike();
1567
1568    uint64 guid;
1569    uint32 unk;
1570    uint32 flags;
1571
1572    recv_data >> guid >> unk >> flags;
1573
1574    _player->SetUnitMovementFlags(flags);
1575    /*
1576    on:
1577    25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
1578    85 4E A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
1579    78 15 94 40 39 03 00 00 | 00 00 80 3F
1580    off:
1581    25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00
1582    10 FD A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
1583    78 15 94 40 39 03 00 00 | 00 00 00 00
1584    */
1585}
1586
1587void WorldSession::HandleRequestPetInfoOpcode( WorldPacket & /*recv_data */)
1588{
1589    /*
1590        sLog.outDebug("WORLD: CMSG_REQUEST_PET_INFO");
1591        recv_data.hexlike();
1592    */
1593}
1594
1595void WorldSession::HandleSetTaxiBenchmarkOpcode( WorldPacket & recv_data )
1596{
1597    CHECK_PACKET_SIZE(recv_data, 1);
1598
1599    uint8 mode;
1600    recv_data >> mode;
1601
1602    sLog.outDebug("Client used \"/timetest %d\" command", mode);
1603}
Note: See TracBrowser for help on using the browser.