Small account data changes
[getmangos.git] / src / game / MiscHandler.cpp
blob1e8861718b20d01cc78fbcb0b39c5e575ae0723f
1 /*
2 * Copyright (C) 2005-2008 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
19 #include "Common.h"
20 #include "Language.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "Opcodes.h"
24 #include "Log.h"
25 #include "Player.h"
26 #include "World.h"
27 #include "ObjectMgr.h"
28 #include "WorldSession.h"
29 #include "Auth/BigNumber.h"
30 #include "Auth/Sha1.h"
31 #include "UpdateData.h"
32 #include "LootMgr.h"
33 #include "Chat.h"
34 #include "ScriptCalls.h"
35 #include <zlib/zlib.h>
36 #include "MapManager.h"
37 #include "ObjectAccessor.h"
38 #include "Object.h"
39 #include "BattleGround.h"
40 #include "SpellAuras.h"
41 #include "Pet.h"
42 #include "SocialMgr.h"
44 void WorldSession::HandleRepopRequestOpcode( WorldPacket & /*recv_data*/ )
46 sLog.outDebug( "WORLD: Recvd CMSG_REPOP_REQUEST Message" );
48 if(GetPlayer()->isAlive()||GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
49 return;
51 // the world update order is sessions, players, creatures
52 // the netcode runs in parallel with all of these
53 // creatures can kill players
54 // so if the server is lagging enough the player can
55 // release spirit after he's killed but before he is updated
56 if(GetPlayer()->getDeathState() == JUST_DIED)
58 sLog.outDebug("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
59 GetPlayer()->KillPlayer();
62 //this is spirit release confirm?
63 GetPlayer()->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
64 GetPlayer()->BuildPlayerRepop();
65 GetPlayer()->RepopAtGraveyard();
68 void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
70 CHECK_PACKET_SIZE(recv_data,4+4+1+1+4+4+4+4);
72 sLog.outDebug( "WORLD: Recvd CMSG_WHO Message" );
73 //recv_data.hexlike();
75 uint32 clientcount = 0;
77 uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
78 uint32 zoneids[10]; // 10 is client limit
79 std::string player_name, guild_name;
81 recv_data >> level_min; // maximal player level, default 0
82 recv_data >> level_max; // minimal player level, default 100
83 recv_data >> player_name; // player name, case sensitive...
85 // recheck
86 CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+1+4+4+4+4);
88 recv_data >> guild_name; // guild name, case sensitive...
90 // recheck
91 CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+4);
93 recv_data >> racemask; // race mask
94 recv_data >> classmask; // class mask
95 recv_data >> zones_count; // zones count, client limit=10 (2.0.10)
97 if(zones_count > 10)
98 return; // can't be received from real client or broken packet
100 // recheck
101 CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4);
103 for(uint32 i = 0; i < zones_count; i++)
105 uint32 temp;
106 recv_data >> temp; // zone id, 0 if zone is unknown...
107 zoneids[i] = temp;
108 sLog.outDebug("Zone %u: %u", i, zoneids[i]);
111 recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10)
113 if(str_count > 4)
114 return; // can't be received from real client or broken packet
116 // recheck
117 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));
119 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);
121 std::wstring str[4]; // 4 is client limit
122 for(uint32 i = 0; i < str_count; i++)
124 // recheck (have one more byte)
125 CHECK_PACKET_SIZE(recv_data,recv_data.rpos());
127 std::string temp;
128 recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)?
130 if(!Utf8toWStr(temp,str[i]))
131 continue;
133 wstrToLower(str[i]);
135 sLog.outDebug("String %u: %s", i, str[i].c_str());
138 std::wstring wplayer_name;
139 std::wstring wguild_name;
140 if(!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
141 return;
142 wstrToLower(wplayer_name);
143 wstrToLower(wguild_name);
145 // client send in case not set max level value 100 but mangos support 255 max level,
146 // update it to show GMs with characters after 100 level
147 if(level_max >= 100)
148 level_max = 255;
150 uint32 team = _player->GetTeam();
151 uint32 security = GetSecurity();
152 bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
153 bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
155 WorldPacket data( SMSG_WHO, 50 ); // guess size
156 data << clientcount; // clientcount place holder
157 data << clientcount; // clientcount place holder
159 //TODO: Guard Player map
160 HashMapHolder<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();
161 for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
163 if (security == SEC_PLAYER)
165 // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
166 if (itr->second->GetTeam() != team && !allowTwoSideWhoList )
167 continue;
169 // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
170 if ((itr->second->GetSession()->GetSecurity() > SEC_PLAYER && !gmInWhoList))
171 continue;
174 // check if target is globally visible for player
175 if (!(itr->second->IsVisibleGloballyFor(_player)))
176 continue;
178 // check if target's level is in level range
179 uint32 lvl = itr->second->getLevel();
180 if (lvl < level_min || lvl > level_max)
181 continue;
183 // check if class matches classmask
184 uint32 class_ = itr->second->getClass();
185 if (!(classmask & (1 << class_)))
186 continue;
188 // check if race matches racemask
189 uint32 race = itr->second->getRace();
190 if (!(racemask & (1 << race)))
191 continue;
193 uint32 pzoneid = itr->second->GetZoneId();
195 bool z_show = true;
196 for(uint32 i = 0; i < zones_count; i++)
198 if(zoneids[i] == pzoneid)
200 z_show = true;
201 break;
204 z_show = false;
206 if (!z_show)
207 continue;
209 std::string pname = itr->second->GetName();
210 std::wstring wpname;
211 if(!Utf8toWStr(pname,wpname))
212 continue;
213 wstrToLower(wpname);
215 if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
216 continue;
218 std::string gname = objmgr.GetGuildNameById(itr->second->GetGuildId());
219 std::wstring wgname;
220 if(!Utf8toWStr(gname,wgname))
221 continue;
222 wstrToLower(wgname);
224 if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
225 continue;
227 std::string aname;
228 if(AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
229 aname = areaEntry->area_name[GetSessionDbcLocale()];
231 bool s_show = true;
232 for(uint32 i = 0; i < str_count; i++)
234 if (!str[i].empty())
236 if (wgname.find(str[i]) != std::wstring::npos ||
237 wpname.find(str[i]) != std::wstring::npos ||
238 Utf8FitTo(aname, str[i]) )
240 s_show = true;
241 break;
243 s_show = false;
246 if (!s_show)
247 continue;
249 data << pname; // player name
250 data << gname; // guild name
251 data << uint32( lvl ); // player level
252 data << uint32( class_ ); // player class
253 data << uint32( race ); // player race
254 data << uint8(0); // new 2.4.0
255 data << uint32( pzoneid ); // player zone id
257 // 49 is maximum player count sent to client
258 if ((++clientcount) == 49)
259 break;
262 data.put( 0, clientcount ); //insert right count
263 data.put( sizeof(uint32), clientcount ); //insert right count
265 SendPacket(&data);
266 sLog.outDebug( "WORLD: Send SMSG_WHO Message" );
269 void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
271 sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity() );
273 if (uint64 lguid = GetPlayer()->GetLootGUID())
274 DoLootRelease(lguid);
276 //instant logout for admins, gm's, mod's
277 if( GetSecurity() > SEC_PLAYER )
279 LogoutPlayer(true);
280 return;
283 //Can not logout if...
284 if( GetPlayer()->isInCombat() || //...is in combat
285 GetPlayer()->duel || //...is in Duel
286 //...is jumping ...is falling
287 GetPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING))
289 WorldPacket data( SMSG_LOGOUT_RESPONSE, (2+4) ) ;
290 data << (uint8)0xC;
291 data << uint32(0);
292 data << uint8(0);
293 SendPacket( &data );
294 LogoutRequest(0);
295 return;
298 //instant logout in taverns/cities or on taxi
299 if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight())
301 LogoutPlayer(true);
302 return;
305 // not set flags if player can't free move to prevent lost state at logout cancel
306 if(GetPlayer()->CanFreeMove())
308 GetPlayer()->SetStandState(PLAYER_STATE_SIT);
310 WorldPacket data( SMSG_FORCE_MOVE_ROOT, (8+4) ); // guess size
311 data.append(GetPlayer()->GetPackGUID());
312 data << (uint32)2;
313 SendPacket( &data );
314 GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
317 WorldPacket data( SMSG_LOGOUT_RESPONSE, 5 );
318 data << uint32(0);
319 data << uint8(0);
320 SendPacket( &data );
321 LogoutRequest(time(NULL));
324 void WorldSession::HandlePlayerLogoutOpcode( WorldPacket & /*recv_data*/ )
326 sLog.outDebug( "WORLD: Recvd CMSG_PLAYER_LOGOUT Message" );
329 void WorldSession::HandleLogoutCancelOpcode( WorldPacket & /*recv_data*/ )
331 sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_CANCEL Message" );
333 LogoutRequest(0);
335 WorldPacket data( SMSG_LOGOUT_CANCEL_ACK, 0 );
336 SendPacket( &data );
338 // not remove flags if can't free move - its not set in Logout request code.
339 if(GetPlayer()->CanFreeMove())
341 //!we can move again
342 data.Initialize( SMSG_FORCE_MOVE_UNROOT, 8 ); // guess size
343 data.append(GetPlayer()->GetPackGUID());
344 data << uint32(0);
345 SendPacket( &data );
347 //! Stand Up
348 GetPlayer()->SetStandState(PLAYER_STATE_NONE);
350 //! DISABLE_ROTATE
351 GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
354 sLog.outDebug( "WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message" );
357 void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text)
359 int len = text ? strlen(text) : 0;
360 WorldPacket data( SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4) );
361 data << uint32(status); // standard 0x0A, 0x06 if text present
362 if(status == 6)
364 data << text; // ticket text
365 data << uint8(0x7); // ticket category
366 data << float(0); // time from ticket creation?
367 data << float(0); // const
368 data << float(0); // const
369 data << uint8(0); // const
370 data << uint8(0); // const
372 SendPacket( &data );
375 void WorldSession::HandleGMTicketGetTicketOpcode( WorldPacket & /*recv_data*/ )
377 WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 );
378 data << (uint32)time(NULL);
379 data << (uint32)0;
380 SendPacket( &data );
382 uint64 guid;
383 Field *fields;
384 guid = GetPlayer()->GetGUID();
386 QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(ticket_id) FROM character_ticket WHERE guid = '%u'", GUID_LOPART(guid));
388 if (result)
390 int cnt;
391 fields = result->Fetch();
392 cnt = fields[0].GetUInt32();
393 delete result;
395 if ( cnt > 0 )
397 QueryResult *result2 = CharacterDatabase.PQuery("SELECT ticket_text FROM character_ticket WHERE guid = '%u'", GUID_LOPART(guid));
398 if(result2)
400 Field *fields2 = result2->Fetch();
401 SendGMTicketGetTicket(0x06,fields2[0].GetString());
402 delete result2;
405 else
406 SendGMTicketGetTicket(0x0A,0);
410 void WorldSession::HandleGMTicketUpdateTextOpcode( WorldPacket & recv_data )
412 CHECK_PACKET_SIZE(recv_data,1);
414 std::string ticketText;
415 recv_data >> ticketText;
417 CharacterDatabase.escape_string(ticketText);
418 CharacterDatabase.PExecute("UPDATE character_ticket SET ticket_text = '%s' WHERE guid = '%u'", ticketText.c_str(), _player->GetGUIDLow());
421 void WorldSession::HandleGMTicketDeleteOpcode( WorldPacket & /*recv_data*/ )
423 uint32 guid = GetPlayer()->GetGUIDLow();
425 CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u' LIMIT 1",guid);
427 WorldPacket data( SMSG_GMTICKET_DELETETICKET, 4 );
428 data << uint32(9);
429 SendPacket( &data );
431 SendGMTicketGetTicket(0x0A, 0);
434 void WorldSession::HandleGMTicketCreateOpcode( WorldPacket & recv_data )
436 CHECK_PACKET_SIZE(recv_data, 4*4+1+2*4);
438 uint32 map;
439 float x, y, z;
440 std::string ticketText = "";
441 uint32 unk1, unk2;
443 recv_data >> map >> x >> y >> z; // last check 2.4.3
444 recv_data >> ticketText;
446 // recheck
447 CHECK_PACKET_SIZE(recv_data,4*4+(ticketText.size()+1)+2*4);
449 recv_data >> unk1 >> unk2;
450 // note: the packet might contain more data, but the exact structure of that is unknown
452 sLog.outDebug("TicketCreate: map %u, x %f, y %f, z %f, text %s, unk1 %u, unk2 %u", map, x, y, z, ticketText.c_str(), unk1, unk2);
454 CharacterDatabase.escape_string(ticketText);
456 QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM character_ticket WHERE guid = '%u'", _player->GetGUIDLow());
458 if (result)
460 int cnt;
461 Field *fields = result->Fetch();
462 cnt = fields[0].GetUInt32();
463 delete result;
465 if ( cnt > 0 )
467 WorldPacket data( SMSG_GMTICKET_CREATE, 4 );
468 data << uint32(1);
469 SendPacket( &data );
471 else
473 CharacterDatabase.PExecute("INSERT INTO character_ticket (guid,ticket_text) VALUES ('%u', '%s')", _player->GetGUIDLow(), ticketText.c_str());
475 WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 );
476 data << (uint32)time(NULL);
477 data << (uint32)0;
478 SendPacket( &data );
480 data.Initialize( SMSG_GMTICKET_CREATE, 4 );
481 data << uint32(2);
482 SendPacket( &data );
483 DEBUG_LOG("update the ticket\n");
485 //TODO: Guard player map
486 HashMapHolder<Player>::MapType &m = ObjectAccessor::Instance().GetPlayers();
487 for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
489 if(itr->second->GetSession()->GetSecurity() >= SEC_GAMEMASTER && itr->second->isAcceptTickets())
490 ChatHandler(itr->second).PSendSysMessage(LANG_COMMAND_TICKETNEW,GetPlayer()->GetName());
496 void WorldSession::HandleGMTicketSystemStatusOpcode( WorldPacket & /*recv_data*/ )
498 WorldPacket data( SMSG_GMTICKET_SYSTEMSTATUS,4 );
499 data << uint32(1); // we can also disable ticket system by sending 0 value
501 SendPacket( &data );
504 void WorldSession::HandleGMSurveySubmit( WorldPacket & recv_data)
506 // GM survey is shown after SMSG_GM_TICKET_STATUS_UPDATE with status = 3
507 CHECK_PACKET_SIZE(recv_data,4+4);
508 uint32 x;
509 recv_data >> x; // answer range? (6 = 0-5?)
510 sLog.outDebug("SURVEY: X = %u", x);
512 uint8 result[10];
513 memset(result, 0, sizeof(result));
514 for( int i = 0; i < 10; ++i)
516 CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+4);
517 uint32 questionID;
518 recv_data >> questionID; // GMSurveyQuestions.dbc
519 if (!questionID)
520 break;
522 CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+1+1);
523 uint8 value;
524 std::string unk_text;
525 recv_data >> value; // answer
526 recv_data >> unk_text; // always empty?
528 result[i] = value;
529 sLog.outDebug("SURVEY: ID %u, value %u, text %s", questionID, value, unk_text.c_str());
532 CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+1);
533 std::string comment;
534 recv_data >> comment; // addional comment
535 sLog.outDebug("SURVEY: comment %s", comment.c_str());
537 // TODO: chart this data in some way
540 void WorldSession::HandleTogglePvP( WorldPacket & recv_data )
542 // this opcode can be used in two ways: Either set explicit new status or toggle old status
543 if(recv_data.size() == 1)
545 bool newPvPStatus;
546 recv_data >> newPvPStatus;
547 GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus);
548 GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP, newPvPStatus);
550 else
552 GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP);
553 GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP);
556 if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
558 if(!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0)
559 GetPlayer()->UpdatePvP(true, true);
561 else
563 if(!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP())
564 GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off
568 void WorldSession::HandleZoneUpdateOpcode( WorldPacket & recv_data )
570 CHECK_PACKET_SIZE(recv_data,4);
572 uint32 newZone;
573 recv_data >> newZone;
575 sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone);
577 if(newZone != _player->GetZoneId())
578 GetPlayer()->SendInitWorldStates(); // only if really enters to new zone, not just area change, works strange...
580 GetPlayer()->UpdateZone(newZone);
583 void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data )
585 // When this packet send?
586 CHECK_PACKET_SIZE(recv_data,8);
588 uint64 guid ;
589 recv_data >> guid;
591 _player->SetUInt32Value(UNIT_FIELD_TARGET,guid);
593 // update reputation list if need
594 Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
595 if(!unit)
596 return;
598 _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
601 void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
603 CHECK_PACKET_SIZE(recv_data,8);
605 uint64 guid;
606 recv_data >> guid;
608 _player->SetSelection(guid);
610 // update reputation list if need
611 Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
612 if(!unit)
613 return;
615 _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
618 void WorldSession::HandleStandStateChangeOpcode( WorldPacket & recv_data )
620 CHECK_PACKET_SIZE(recv_data,1);
622 sLog.outDebug( "WORLD: Received CMSG_STAND_STATE_CHANGE" );
623 uint8 animstate;
624 recv_data >> animstate;
626 _player->SetStandState(animstate);
629 void WorldSession::HandleFriendListOpcode( WorldPacket & recv_data )
631 CHECK_PACKET_SIZE(recv_data, 4);
632 sLog.outDebug( "WORLD: Received CMSG_CONTACT_LIST" );
633 uint32 unk;
634 recv_data >> unk;
635 sLog.outDebug("unk value is %u", unk);
636 _player->GetSocial()->SendSocialList();
639 void WorldSession::HandleAddFriendOpcode( WorldPacket & recv_data )
641 CHECK_PACKET_SIZE(recv_data, 1+1);
643 sLog.outDebug( "WORLD: Received CMSG_ADD_FRIEND" );
645 std::string friendName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
646 std::string friendNote;
647 FriendsResult friendResult = FRIEND_NOT_FOUND;
648 Player *pFriend = NULL;
649 uint64 friendGuid = 0;
651 recv_data >> friendName;
653 // recheck
654 CHECK_PACKET_SIZE(recv_data, (friendName.size()+1)+1);
656 recv_data >> friendNote;
658 if(!normalizePlayerName(friendName))
659 return;
661 CharacterDatabase.escape_string(friendName); // prevent SQL injection - normal name don't must changed by this call
663 sLog.outDebug( "WORLD: %s asked to add friend : '%s'",
664 GetPlayer()->GetName(), friendName.c_str() );
666 friendGuid = objmgr.GetPlayerGUIDByName(friendName);
668 if(friendGuid)
670 pFriend = ObjectAccessor::FindPlayer(friendGuid);
671 if(pFriend==GetPlayer())
672 friendResult = FRIEND_SELF;
673 else if(GetPlayer()->GetTeam()!=objmgr.GetPlayerTeamByGUID(friendGuid) && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && GetSecurity() < SEC_MODERATOR)
674 friendResult = FRIEND_ENEMY;
675 else if(GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
676 friendResult = FRIEND_ALREADY;
679 if (friendGuid && friendResult==FRIEND_NOT_FOUND)
681 if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(GetPlayer()))
682 friendResult = FRIEND_ADDED_ONLINE;
683 else
684 friendResult = FRIEND_ADDED_OFFLINE;
686 if(!_player->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
688 friendResult = FRIEND_LIST_FULL;
689 sLog.outDebug( "WORLD: %s's friend list is full.", GetPlayer()->GetName());
692 _player->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote);
694 sLog.outDebug( "WORLD: %s Guid found '%u'.", friendName.c_str(), GUID_LOPART(friendGuid));
696 else if(friendResult==FRIEND_ALREADY)
698 sLog.outDebug( "WORLD: %s Guid Already a Friend.", friendName.c_str() );
700 else if(friendResult==FRIEND_SELF)
702 sLog.outDebug( "WORLD: %s Guid can't add himself.", friendName.c_str() );
704 else
706 sLog.outDebug( "WORLD: %s Guid not found.", friendName.c_str() );
709 sSocialMgr.SendFriendStatus(GetPlayer(), friendResult, GUID_LOPART(friendGuid), friendName, false);
711 sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
714 void WorldSession::HandleDelFriendOpcode( WorldPacket & recv_data )
716 CHECK_PACKET_SIZE(recv_data, 8);
718 uint64 FriendGUID;
720 sLog.outDebug( "WORLD: Received CMSG_DEL_FRIEND" );
722 recv_data >> FriendGUID;
724 _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false);
726 sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), "", false);
728 sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
731 void WorldSession::HandleAddIgnoreOpcode( WorldPacket & recv_data )
733 CHECK_PACKET_SIZE(recv_data,1);
735 sLog.outDebug( "WORLD: Received CMSG_ADD_IGNORE" );
737 std::string IgnoreName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
738 FriendsResult ignoreResult = FRIEND_IGNORE_NOT_FOUND;
739 uint64 IgnoreGuid = 0;
741 recv_data >> IgnoreName;
743 if(!normalizePlayerName(IgnoreName))
744 return;
746 CharacterDatabase.escape_string(IgnoreName); // prevent SQL injection - normal name don't must changed by this call
748 sLog.outDebug( "WORLD: %s asked to Ignore: '%s'",
749 GetPlayer()->GetName(), IgnoreName.c_str() );
751 IgnoreGuid = objmgr.GetPlayerGUIDByName(IgnoreName);
753 if(IgnoreGuid)
755 if(IgnoreGuid==GetPlayer()->GetGUID())
756 ignoreResult = FRIEND_IGNORE_SELF;
757 else
759 if( GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid)) )
760 ignoreResult = FRIEND_IGNORE_ALREADY;
764 if (IgnoreGuid && ignoreResult == FRIEND_IGNORE_NOT_FOUND)
766 ignoreResult = FRIEND_IGNORE_ADDED;
768 if(!_player->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true))
769 ignoreResult = FRIEND_IGNORE_FULL;
771 else if(ignoreResult==FRIEND_IGNORE_ALREADY)
773 sLog.outDebug( "WORLD: %s Guid Already Ignored.", IgnoreName.c_str() );
775 else if(ignoreResult==FRIEND_IGNORE_SELF)
777 sLog.outDebug( "WORLD: %s Guid can't add himself.", IgnoreName.c_str() );
779 else
781 sLog.outDebug( "WORLD: %s Guid not found.", IgnoreName.c_str() );
784 sSocialMgr.SendFriendStatus(GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), "", false);
786 sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
789 void WorldSession::HandleDelIgnoreOpcode( WorldPacket & recv_data )
791 CHECK_PACKET_SIZE(recv_data, 8);
793 uint64 IgnoreGUID;
795 sLog.outDebug( "WORLD: Received CMSG_DEL_IGNORE" );
797 recv_data >> IgnoreGUID;
799 _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true);
801 sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), "", false);
803 sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
806 void WorldSession::HandleSetFriendNoteOpcode( WorldPacket & recv_data )
808 CHECK_PACKET_SIZE(recv_data, 8+1);
809 uint64 guid;
810 std::string note;
811 recv_data >> guid >> note;
812 _player->GetSocial()->SetFriendNote(guid, note);
815 void WorldSession::HandleBugOpcode( WorldPacket & recv_data )
817 CHECK_PACKET_SIZE(recv_data,4+4+1+4+1);
819 uint32 suggestion, contentlen;
820 std::string content;
821 uint32 typelen;
822 std::string type;
824 recv_data >> suggestion >> contentlen >> content;
826 //recheck
827 CHECK_PACKET_SIZE(recv_data,4+4+(content.size()+1)+4+1);
829 recv_data >> typelen >> type;
831 if( suggestion == 0 )
832 sLog.outDebug( "WORLD: Received CMSG_BUG [Bug Report]" );
833 else
834 sLog.outDebug( "WORLD: Received CMSG_BUG [Suggestion]" );
836 sLog.outDebug( type.c_str( ) );
837 sLog.outDebug( content.c_str( ) );
839 CharacterDatabase.escape_string(type);
840 CharacterDatabase.escape_string(content);
841 CharacterDatabase.PExecute ("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type.c_str( ), content.c_str( ));
844 void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data)
846 CHECK_PACKET_SIZE(recv_data,8);
848 sLog.outDetail("WORLD: Received CMSG_RECLAIM_CORPSE");
849 if (GetPlayer()->isAlive())
850 return;
852 // body not released yet
853 if(!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
854 return;
856 Corpse *corpse = GetPlayer()->GetCorpse();
858 if (!corpse )
859 return;
861 // prevent resurrect before 30-sec delay after body release not finished
862 if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL))
863 return;
865 float dist = corpse->GetDistance2d(GetPlayer());
866 sLog.outDebug("Corpse 2D Distance: \t%f",dist);
867 if (dist > CORPSE_RECLAIM_RADIUS)
868 return;
870 uint64 guid;
871 recv_data >> guid;
873 // resurrect
874 GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f : 0.5f);
876 // spawn bones
877 GetPlayer()->SpawnCorpseBones();
879 GetPlayer()->SaveToDB();
882 void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data)
884 CHECK_PACKET_SIZE(recv_data,8+1);
886 sLog.outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE");
888 if(GetPlayer()->isAlive())
889 return;
891 uint64 guid;
892 uint8 status;
893 recv_data >> guid;
894 recv_data >> status;
896 if(status == 0)
898 GetPlayer()->clearResurrectRequestData(); // reject
899 return;
902 if(!GetPlayer()->isRessurectRequestedBy(guid))
903 return;
905 GetPlayer()->ResurectUsingRequestData();
906 GetPlayer()->SaveToDB();
909 void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
911 CHECK_PACKET_SIZE(recv_data,4);
913 sLog.outDebug("WORLD: Received CMSG_AREATRIGGER");
915 uint32 Trigger_ID;
917 recv_data >> Trigger_ID;
918 sLog.outDebug("Trigger ID:%u",Trigger_ID);
920 if(GetPlayer()->isInFlight())
922 sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
923 return;
926 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
927 if(!atEntry)
929 sLog.outDebug("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
930 return;
933 if (GetPlayer()->GetMapId()!=atEntry->mapid)
935 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);
936 return;
939 // delta is safe radius
940 const float delta = 5.0f;
941 // check if player in the range of areatrigger
942 Player* pl = GetPlayer();
944 if (atEntry->radius > 0)
946 // if we have radius check it
947 float dist = pl->GetDistance(atEntry->x,atEntry->y,atEntry->z);
948 if(dist > atEntry->radius + delta)
950 sLog.outDebug("Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u",
951 pl->GetName(), pl->GetGUIDLow(), atEntry->radius, dist, Trigger_ID);
952 return;
955 else
957 // we have only extent
958 float dx = pl->GetPositionX() - atEntry->x;
959 float dy = pl->GetPositionY() - atEntry->y;
960 float dz = pl->GetPositionZ() - atEntry->z;
961 double es = sin(atEntry->box_orientation);
962 double ec = cos(atEntry->box_orientation);
963 // calc rotated vector based on extent axis
964 double rotateDx = dx*ec - dy*es;
965 double rotateDy = dx*es + dy*ec;
967 if( (fabs(rotateDx) > atEntry->box_x/2 + delta) ||
968 (fabs(rotateDy) > atEntry->box_y/2 + delta) ||
969 (fabs(dz) > atEntry->box_z/2 + delta) )
971 sLog.outDebug("Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %u 1/2 box Z: %u rotate dX: %f rotate dY: %f dZ:%f), ignore Area Trigger ID: %u",
972 pl->GetName(), pl->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotateDx, rotateDy, dz, Trigger_ID);
973 return;
977 if(Script->scriptAreaTrigger(GetPlayer(), atEntry))
978 return;
980 uint32 quest_id = objmgr.GetQuestForAreaTrigger( Trigger_ID );
981 if( quest_id && GetPlayer()->isAlive() && GetPlayer()->IsActiveQuest(quest_id) )
983 Quest const* pQuest = objmgr.GetQuestTemplate(quest_id);
984 if( pQuest )
986 if(GetPlayer()->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE)
987 GetPlayer()->AreaExploredOrEventHappens( quest_id );
991 if(objmgr.IsTavernAreaTrigger(Trigger_ID))
993 // set resting flag we are in the inn
994 GetPlayer()->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
995 GetPlayer()->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z);
996 GetPlayer()->SetRestType(REST_TYPE_IN_TAVERN);
998 if(sWorld.IsFFAPvPRealm())
999 GetPlayer()->RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
1001 return;
1004 if(GetPlayer()->InBattleGround())
1006 BattleGround* bg = GetPlayer()->GetBattleGround();
1007 if(bg)
1008 if(bg->GetStatus() == STATUS_IN_PROGRESS)
1009 bg->HandleAreaTrigger(GetPlayer(), Trigger_ID);
1011 return;
1014 // NULL if all values default (non teleport trigger)
1015 AreaTrigger const* at = objmgr.GetAreaTrigger(Trigger_ID);
1016 if(!at)
1017 return;
1019 if(!GetPlayer()->isGameMaster())
1021 uint32 missingLevel = 0;
1022 if(GetPlayer()->getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
1023 missingLevel = at->requiredLevel;
1025 // must have one or the other, report the first one that's missing
1026 uint32 missingItem = 0;
1027 if(at->requiredItem)
1029 if(!GetPlayer()->HasItemCount(at->requiredItem, 1) &&
1030 (!at->requiredItem2 || !GetPlayer()->HasItemCount(at->requiredItem2, 1)))
1031 missingItem = at->requiredItem;
1033 else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1))
1034 missingItem = at->requiredItem2;
1036 uint32 missingKey = 0;
1037 if(GetPlayer()->GetDifficulty() == DIFFICULTY_HEROIC)
1039 if(at->heroicKey)
1041 if(!GetPlayer()->HasItemCount(at->heroicKey, 1) &&
1042 (!at->heroicKey2 || !GetPlayer()->HasItemCount(at->heroicKey2, 1)))
1043 missingKey = at->heroicKey;
1045 else if(at->heroicKey2 && !GetPlayer()->HasItemCount(at->heroicKey2, 1))
1046 missingKey = at->heroicKey2;
1049 uint32 missingQuest = 0;
1050 if(at->requiredQuest && !GetPlayer()->GetQuestRewardStatus(at->requiredQuest))
1051 missingQuest = at->requiredQuest;
1053 if(missingLevel || missingItem || missingKey || missingQuest)
1055 // TODO: all this is probably wrong
1056 if(missingItem)
1057 SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1);
1058 else if(missingKey)
1059 GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, DIFFICULTY_HEROIC);
1060 else if(missingQuest)
1061 SendAreaTriggerMessage(at->requiredFailedText.c_str());
1062 else if(missingLevel)
1063 SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), missingLevel);
1064 return;
1068 GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,TELE_TO_NOT_LEAVE_TRANSPORT);
1071 void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data)
1073 sLog.outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA");
1075 CHECK_PACKET_SIZE(recv_data, 4+4+4);
1077 uint32 type, timestamp, decompressedSize;
1078 recv_data >> type >> timestamp >> decompressedSize;
1080 if(type > NUM_ACCOUNT_DATA_TYPES)
1081 return;
1083 if(decompressedSize == 0) // erase
1085 SetAccountData(type, timestamp, "");
1087 WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4);
1088 data << uint32(type);
1089 data << uint32(0);
1090 SendPacket(&data);
1092 return;
1095 if(decompressedSize > 0xFFFF)
1097 sLog.outError("UAD: Account data packet too big, size %u", decompressedSize);
1098 return;
1101 ByteBuffer dest;
1102 dest.resize(decompressedSize);
1104 uLongf realSize = decompressedSize;
1105 if(uncompress(const_cast<uint8*>(dest.contents()), &realSize, const_cast<uint8*>(recv_data.contents() + recv_data.rpos()), recv_data.size() - recv_data.rpos()) != Z_OK)
1107 sLog.outError("UAD: Failed to decompress account data");
1108 return;
1111 std::string adata;
1112 dest >> adata;
1114 SetAccountData(type, timestamp, adata);
1116 WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4);
1117 data << uint32(type);
1118 data << uint32(0);
1119 SendPacket(&data);
1122 void WorldSession::HandleRequestAccountData(WorldPacket& recv_data)
1124 sLog.outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA");
1126 CHECK_PACKET_SIZE(recv_data, 4);
1128 uint32 type;
1129 recv_data >> type;
1131 if(type > NUM_ACCOUNT_DATA_TYPES)
1132 return;
1134 AccountData *adata = GetAccountData(type);
1136 uint32 size = adata->Data.size();
1138 ByteBuffer dest(size);
1140 uLongf destSize = size;
1141 if(compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK)
1143 sLog.outDebug("RAD: Failed to compress account data");
1144 return;
1147 dest.resize(destSize);
1149 WorldPacket data (SMSG_UPDATE_ACCOUNT_DATA, 8+4+4+4+destSize);
1150 data << uint64(_player->GetGUID()); // player guid
1151 data << uint32(type); // type (0-7)
1152 data << uint32(adata->Time); // unix time
1153 data << uint32(size); // decompressed length
1154 data.append(dest); // compressed data
1155 SendPacket(&data);
1158 void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
1160 CHECK_PACKET_SIZE(recv_data,1+2+1+1);
1162 sLog.outDebug( "WORLD: Received CMSG_SET_ACTION_BUTTON" );
1163 uint8 button, misc, type;
1164 uint16 action;
1165 recv_data >> button >> action >> misc >> type;
1166 sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u MISC: %u", button, action, type, misc );
1167 if(action==0)
1169 sLog.outDetail( "MISC: Remove action from button %u", button );
1171 GetPlayer()->removeActionButton(button);
1173 else
1175 if(type==ACTION_BUTTON_MACRO || type==ACTION_BUTTON_CMACRO)
1177 sLog.outDetail( "MISC: Added Macro %u into button %u", action, button );
1178 GetPlayer()->addActionButton(button,action,type,misc);
1180 else if(type==ACTION_BUTTON_SPELL)
1182 sLog.outDetail( "MISC: Added Action %u into button %u", action, button );
1183 GetPlayer()->addActionButton(button,action,type,misc);
1185 else if(type==ACTION_BUTTON_ITEM)
1187 sLog.outDetail( "MISC: Added Item %u into button %u", action, button );
1188 GetPlayer()->addActionButton(button,action,type,misc);
1190 else
1191 sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button );
1195 void WorldSession::HandleCompleteCinema( WorldPacket & /*recv_data*/ )
1197 DEBUG_LOG( "WORLD: Player is watching cinema" );
1200 void WorldSession::HandleNextCinematicCamera( WorldPacket & /*recv_data*/ )
1202 DEBUG_LOG( "WORLD: Which movie to play" );
1205 void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & /*recv_data*/ )
1207 /* WorldSession::Update( getMSTime() );*/
1208 DEBUG_LOG( "WORLD: Time Lag/Synchronization Resent/Update" );
1211 CHECK_PACKET_SIZE(recv_data,8+4);
1212 uint64 guid;
1213 uint32 time_skipped;
1214 recv_data >> guid;
1215 recv_data >> time_skipped;
1216 sLog.outDebug( "WORLD: CMSG_MOVE_TIME_SKIPPED" );
1218 /// TODO
1219 must be need use in mangos
1220 We substract server Lags to move time ( AntiLags )
1221 for exmaple
1222 GetPlayer()->ModifyLastMoveTime( -int32(time_skipped) );
1226 void WorldSession::HandleFeatherFallAck(WorldPacket &/*recv_data*/)
1228 DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
1231 void WorldSession::HandleMoveUnRootAck(WorldPacket&/* recv_data*/)
1234 CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
1236 sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK" );
1237 recv_data.hexlike();
1238 uint64 guid;
1239 uint64 unknown1;
1240 uint32 unknown2;
1241 float PositionX;
1242 float PositionY;
1243 float PositionZ;
1244 float Orientation;
1246 recv_data >> guid;
1247 recv_data >> unknown1;
1248 recv_data >> unknown2;
1249 recv_data >> PositionX;
1250 recv_data >> PositionY;
1251 recv_data >> PositionZ;
1252 recv_data >> Orientation;
1254 // TODO for later may be we can use for anticheat
1255 DEBUG_LOG("Guid " I64FMTD,guid);
1256 DEBUG_LOG("unknown1 " I64FMTD,unknown1);
1257 DEBUG_LOG("unknown2 %u",unknown2);
1258 DEBUG_LOG("X %f",PositionX);
1259 DEBUG_LOG("Y %f",PositionY);
1260 DEBUG_LOG("Z %f",PositionZ);
1261 DEBUG_LOG("O %f",Orientation);
1265 void WorldSession::HandleMoveRootAck(WorldPacket&/* recv_data*/)
1268 CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
1270 sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_ROOT_ACK" );
1271 recv_data.hexlike();
1272 uint64 guid;
1273 uint64 unknown1;
1274 uint32 unknown2;
1275 float PositionX;
1276 float PositionY;
1277 float PositionZ;
1278 float Orientation;
1280 recv_data >> guid;
1281 recv_data >> unknown1;
1282 recv_data >> unknown2;
1283 recv_data >> PositionX;
1284 recv_data >> PositionY;
1285 recv_data >> PositionZ;
1286 recv_data >> Orientation;
1288 // for later may be we can use for anticheat
1289 DEBUG_LOG("Guid " I64FMTD,guid);
1290 DEBUG_LOG("unknown1 " I64FMTD,unknown1);
1291 DEBUG_LOG("unknown1 %u",unknown2);
1292 DEBUG_LOG("X %f",PositionX);
1293 DEBUG_LOG("Y %f",PositionY);
1294 DEBUG_LOG("Z %f",PositionZ);
1295 DEBUG_LOG("O %f",Orientation);
1299 void WorldSession::HandleMoveTeleportAck(WorldPacket&/* recv_data*/)
1302 CHECK_PACKET_SIZE(recv_data,8+4);
1304 sLog.outDebug("MSG_MOVE_TELEPORT_ACK");
1305 uint64 guid;
1306 uint32 flags, time;
1308 recv_data >> guid;
1309 recv_data >> flags >> time;
1310 DEBUG_LOG("Guid " I64FMTD,guid);
1311 DEBUG_LOG("Flags %u, time %u",flags, time/1000);
1315 void WorldSession::HandleSetActionBar(WorldPacket& recv_data)
1317 CHECK_PACKET_SIZE(recv_data,1);
1319 uint8 ActionBar;
1321 recv_data >> ActionBar;
1323 if(!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED)
1325 if(ActionBar!=0)
1326 sLog.outError("WorldSession::HandleSetActionBar in not logged state with value: %u, ignored",uint32(ActionBar));
1327 return;
1330 GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar);
1333 void WorldSession::HandleWardenDataOpcode(WorldPacket& /*recv_data*/)
1336 CHECK_PACKET_SIZE(recv_data,1);
1338 uint8 tmp;
1339 recv_data >> tmp;
1340 sLog.outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u",tmp);
1344 void WorldSession::HandlePlayedTime(WorldPacket& /*recv_data*/)
1346 uint32 TotalTimePlayed = GetPlayer()->GetTotalPlayedTime();
1347 uint32 LevelPlayedTime = GetPlayer()->GetLevelPlayedTime();
1349 WorldPacket data(SMSG_PLAYED_TIME, 8);
1350 data << TotalTimePlayed;
1351 data << LevelPlayedTime;
1352 SendPacket(&data);
1355 void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
1357 CHECK_PACKET_SIZE(recv_data, 8);
1359 uint64 guid;
1360 recv_data >> guid;
1361 DEBUG_LOG("Inspected guid is " I64FMTD, guid);
1363 _player->SetSelection(guid);
1365 Player *plr = objmgr.GetPlayer(guid);
1366 if(!plr) // wrong player
1367 return;
1369 uint32 talent_points = 0x3D;
1370 uint32 guid_size = plr->GetPackGUID().size();
1371 WorldPacket data(SMSG_INSPECT_TALENT, 4+talent_points);
1372 data.append(plr->GetPackGUID());
1373 data << uint32(talent_points);
1375 // fill by 0 talents array
1376 for(uint32 i = 0; i < talent_points; ++i)
1377 data << uint8(0);
1379 if(sWorld.getConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster())
1381 // find class talent tabs (all players have 3 talent tabs)
1382 uint32 const* talentTabIds = GetTalentTabPages(plr->getClass());
1384 uint32 talentTabPos = 0; // pos of first talent rank in tab including all prev tabs
1385 for(uint32 i = 0; i < 3; ++i)
1387 uint32 talentTabId = talentTabIds[i];
1389 // fill by real data
1390 for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
1392 TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
1393 if(!talentInfo)
1394 continue;
1396 // skip another tab talents
1397 if(talentInfo->TalentTab != talentTabId)
1398 continue;
1400 // find talent rank
1401 uint32 curtalent_maxrank = 0;
1402 for(uint32 k = 5; k > 0; --k)
1404 if(talentInfo->RankID[k-1] && plr->HasSpell(talentInfo->RankID[k-1]))
1406 curtalent_maxrank = k;
1407 break;
1411 // not learned talent
1412 if(!curtalent_maxrank)
1413 continue;
1415 // 1 rank talent bit index
1416 uint32 curtalent_index = talentTabPos + GetTalentInspectBitPosInTab(talentId);
1418 uint32 curtalent_rank_index = curtalent_index+curtalent_maxrank-1;
1420 // slot/offset in 7-bit bytes
1421 uint32 curtalent_rank_slot7 = curtalent_rank_index / 7;
1422 uint32 curtalent_rank_offset7 = curtalent_rank_index % 7;
1424 // rank pos with skipped 8 bit
1425 uint32 curtalent_rank_index2 = curtalent_rank_slot7 * 8 + curtalent_rank_offset7;
1427 // slot/offset in 8-bit bytes with skipped high bit
1428 uint32 curtalent_rank_slot = curtalent_rank_index2 / 8;
1429 uint32 curtalent_rank_offset = curtalent_rank_index2 % 8;
1431 // apply mask
1432 uint32 val = data.read<uint8>(guid_size + 4 + curtalent_rank_slot);
1433 val |= (1 << curtalent_rank_offset);
1434 data.put<uint8>(guid_size + 4 + curtalent_rank_slot, val & 0xFF);
1437 talentTabPos += GetTalentTabInspectBitSize(talentTabId);
1441 SendPacket(&data);
1444 void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data)
1446 CHECK_PACKET_SIZE(recv_data, 8);
1448 uint64 guid;
1449 recv_data >> guid;
1451 Player *player = objmgr.GetPlayer(guid);
1453 if(!player)
1455 sLog.outError("InspectHonorStats: WTF, player not found...");
1456 return;
1459 WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4);
1460 data << uint64(player->GetGUID());
1461 data << uint8(player->GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY));
1462 data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS));
1463 data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION));
1464 data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION));
1465 data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS));
1466 SendPacket(&data);
1469 void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data)
1471 CHECK_PACKET_SIZE(recv_data,4+4+4+4+4+4);
1473 // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180
1474 // Received opcode CMSG_WORLD_TELEPORT
1475 // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593
1477 //sLog.outDebug("Received opcode CMSG_WORLD_TELEPORT");
1479 if(GetPlayer()->isInFlight())
1481 sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore worldport command.",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow());
1482 return;
1485 uint32 time;
1486 uint32 mapid;
1487 float PositionX;
1488 float PositionY;
1489 float PositionZ;
1490 float Orientation;
1492 recv_data >> time; // time in m.sec.
1493 recv_data >> mapid;
1494 recv_data >> PositionX;
1495 recv_data >> PositionY;
1496 recv_data >> PositionZ;
1497 recv_data >> Orientation; // o (3.141593 = 180 degrees)
1498 DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation);
1500 if (GetSecurity() >= SEC_ADMINISTRATOR)
1501 GetPlayer()->TeleportTo(mapid,PositionX,PositionY,PositionZ,Orientation);
1502 else
1503 SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
1504 sLog.outDebug("Received worldport command from player %s", GetPlayer()->GetName());
1507 void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
1509 CHECK_PACKET_SIZE(recv_data, 1);
1511 sLog.outDebug("Received opcode CMSG_WHOIS");
1512 std::string charname;
1513 recv_data >> charname;
1515 if (GetSecurity() < SEC_ADMINISTRATOR)
1517 SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
1518 return;
1521 if(charname.empty())
1523 SendNotification(LANG_NEED_CHARACTER_NAME);
1524 return;
1527 Player *plr = objmgr.GetPlayer(charname.c_str());
1529 if(!plr)
1531 SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str());
1532 return;
1535 uint32 accid = plr->GetSession()->GetAccountId();
1537 QueryResult *result = loginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
1538 if(!result)
1540 SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str());
1541 return;
1544 Field *fields = result->Fetch();
1545 std::string acc = fields[0].GetCppString();
1546 if(acc.empty())
1547 acc = "Unknown";
1548 std::string email = fields[1].GetCppString();
1549 if(email.empty())
1550 email = "Unknown";
1551 std::string lastip = fields[2].GetCppString();
1552 if(lastip.empty())
1553 lastip = "Unknown";
1555 std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip;
1557 WorldPacket data(SMSG_WHOIS, msg.size()+1);
1558 data << msg;
1559 _player->GetSession()->SendPacket(&data);
1561 delete result;
1563 sLog.outDebug("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str());
1566 void WorldSession::HandleReportSpamOpcode( WorldPacket & recv_data )
1568 CHECK_PACKET_SIZE(recv_data, 1+8);
1569 sLog.outDebug("WORLD: CMSG_REPORT_SPAM");
1570 recv_data.hexlike();
1572 uint8 spam_type; // 0 - mail, 1 - chat
1573 uint64 spammer_guid;
1574 uint32 unk1, unk2, unk3, unk4 = 0;
1575 std::string description = "";
1576 recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat)
1577 recv_data >> spammer_guid; // player guid
1578 switch(spam_type)
1580 case 0:
1581 CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4);
1582 recv_data >> unk1; // const 0
1583 recv_data >> unk2; // probably mail id
1584 recv_data >> unk3; // const 0
1585 break;
1586 case 1:
1587 CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4+4+1);
1588 recv_data >> unk1; // probably language
1589 recv_data >> unk2; // message type?
1590 recv_data >> unk3; // probably channel id
1591 recv_data >> unk4; // unk random value
1592 recv_data >> description; // spam description string (messagetype, channel name, player name, message)
1593 break;
1596 // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam.
1597 // if it's mail spam - ALL mails from this spammer automatically removed by client
1599 // Complaint Received message
1600 WorldPacket data(SMSG_COMPLAIN_RESULT, 1);
1601 data << uint8(0);
1602 SendPacket(&data);
1604 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());
1607 void WorldSession::HandleRealmStateRequestOpcode( WorldPacket & recv_data )
1609 CHECK_PACKET_SIZE(recv_data, 4);
1611 sLog.outDebug("CMSG_REALM_SPLIT");
1613 uint32 unk;
1614 std::string split_date = "01/01/01";
1615 recv_data >> unk;
1617 WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1);
1618 data << unk;
1619 data << uint32(0x00000000); // realm split state
1620 // split states:
1621 // 0x0 realm normal
1622 // 0x1 realm split
1623 // 0x2 realm split pending
1624 data << split_date;
1625 SendPacket(&data);
1626 //sLog.outDebug("response sent %u", unk);
1629 void WorldSession::HandleFarSightOpcode( WorldPacket & recv_data )
1631 CHECK_PACKET_SIZE(recv_data, 1);
1633 sLog.outDebug("WORLD: CMSG_FAR_SIGHT");
1634 //recv_data.hexlike();
1636 uint8 unk;
1637 recv_data >> unk;
1639 switch(unk)
1641 case 0:
1642 //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0)
1643 //SendPacket(&data);
1644 //_player->SetUInt64Value(PLAYER_FARSIGHT, 0);
1645 sLog.outDebug("Removed FarSight from player %u", _player->GetGUIDLow());
1646 break;
1647 case 1:
1648 sLog.outDebug("Added FarSight " I64FMTD " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow());
1649 break;
1653 void WorldSession::HandleChooseTitleOpcode( WorldPacket & recv_data )
1655 CHECK_PACKET_SIZE(recv_data, 4);
1657 sLog.outDebug("CMSG_SET_TITLE");
1659 int32 title;
1660 recv_data >> title;
1662 // -1 at none
1663 if(title > 0 && title < 64)
1665 if(!GetPlayer()->HasFlag64(PLAYER__FIELD_KNOWN_TITLES,uint64(1) << title))
1666 return;
1668 else
1669 title = 0;
1671 GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title);
1674 void WorldSession::HandleAllowMoveAckOpcode( WorldPacket & recv_data )
1676 CHECK_PACKET_SIZE(recv_data, 4+4);
1678 sLog.outDebug("CMSG_ALLOW_MOVE_ACK");
1680 uint32 counter, time_;
1681 recv_data >> counter >> time_;
1683 // time_ seems always more than getMSTime()
1684 uint32 diff = getMSTimeDiff(getMSTime(),time_);
1686 sLog.outDebug("response sent: counter %u, time %u (HEX: %X), ms. time %u, diff %u", counter, time_, time_, getMSTime(), diff);
1689 void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ )
1691 sLog.outDebug("WORLD: CMSG_RESET_INSTANCES");
1692 Group *pGroup = _player->GetGroup();
1693 if(pGroup)
1695 if(pGroup->IsLeader(_player->GetGUID()))
1696 pGroup->ResetInstances(INSTANCE_RESET_ALL, _player);
1698 else
1699 _player->ResetInstances(INSTANCE_RESET_ALL);
1702 void WorldSession::HandleDungeonDifficultyOpcode( WorldPacket & recv_data )
1704 CHECK_PACKET_SIZE(recv_data, 4);
1706 sLog.outDebug("MSG_SET_DUNGEON_DIFFICULTY");
1708 uint32 mode;
1709 recv_data >> mode;
1711 if(mode == _player->GetDifficulty())
1712 return;
1714 if(mode > DIFFICULTY_HEROIC)
1716 sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
1717 return;
1720 // cannot reset while in an instance
1721 Map *map = _player->GetMap();
1722 if(map && map->IsDungeon())
1724 sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow());
1725 return;
1728 if(_player->getLevel() < LEVELREQUIREMENT_HEROIC)
1729 return;
1730 Group *pGroup = _player->GetGroup();
1731 if(pGroup)
1733 if(pGroup->IsLeader(_player->GetGUID()))
1735 // the difficulty is set even if the instances can't be reset
1736 //_player->SendDungeonDifficulty(true);
1737 pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player);
1738 pGroup->SetDifficulty(mode);
1741 else
1743 _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY);
1744 _player->SetDifficulty(mode);
1748 void WorldSession::HandleNewUnknownOpcode( WorldPacket & recv_data )
1750 sLog.outDebug("New Unknown Opcode %u", recv_data.GetOpcode());
1751 recv_data.hexlike();
1753 New Unknown Opcode 837
1754 STORAGE_SIZE: 60
1755 02 00 00 00 00 00 00 00 | 00 00 00 00 01 20 00 00
1756 89 EB 33 01 71 5C 24 C4 | 15 03 35 45 74 47 8B 42
1757 BA B8 1B 40 00 00 00 00 | 00 00 00 00 77 66 42 BF
1758 23 91 26 3F 00 00 60 41 | 00 00 00 00
1760 New Unknown Opcode 837
1761 STORAGE_SIZE: 44
1762 02 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
1763 7B 80 34 01 84 EA 2B C4 | 5F A1 36 45 C9 39 1C 42
1764 BA B8 1B 40 CE 06 00 00 | 00 00 80 3F
1768 void WorldSession::HandleDismountOpcode( WorldPacket & /*recv_data*/ )
1770 sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA");
1771 //recv_data.hexlike();
1773 //If player is not mounted, so go out :)
1774 if (!_player->IsMounted()) // not blizz like; no any messages on blizz
1776 ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED);
1777 return;
1780 if(_player->isInFlight()) // not blizz like; no any messages on blizz
1782 ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT);
1783 return;
1786 _player->Unmount();
1787 _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
1790 void WorldSession::HandleMoveFlyModeChangeAckOpcode( WorldPacket & recv_data )
1792 CHECK_PACKET_SIZE(recv_data, 8+4+4);
1794 // fly mode on/off
1795 sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
1796 //recv_data.hexlike();
1798 uint64 guid;
1799 uint32 unk;
1800 uint32 flags;
1802 recv_data >> guid >> unk >> flags;
1804 _player->SetUnitMovementFlags(flags);
1807 25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
1808 85 4E A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
1809 78 15 94 40 39 03 00 00 | 00 00 80 3F
1810 off:
1811 25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00
1812 10 FD A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
1813 78 15 94 40 39 03 00 00 | 00 00 00 00
1817 void WorldSession::HandleRequestPetInfoOpcode( WorldPacket & /*recv_data */)
1820 sLog.outDebug("WORLD: CMSG_REQUEST_PET_INFO");
1821 recv_data.hexlike();
1825 void WorldSession::HandleSetTaxiBenchmarkOpcode( WorldPacket & recv_data )
1827 CHECK_PACKET_SIZE(recv_data, 1);
1829 uint8 mode;
1830 recv_data >> mode;
1832 sLog.outDebug("Client used \"/timetest %d\" command", mode);
1835 void WorldSession::HandleSpellClick( WorldPacket & recv_data )
1837 CHECK_PACKET_SIZE(recv_data, 8);
1839 uint64 guid;
1840 recv_data >> guid;
1842 Unit *vehicle = ObjectAccessor::GetUnit(*_player, guid);
1844 if(!vehicle)
1845 return;
1847 _player->SetClientControl(vehicle, 1);
1848 _player->CastSpell(_player, 43768, true);
1849 _player->SetUInt64Value(UNIT_FIELD_CHARM, guid);
1850 _player->SetUInt64Value(PLAYER_FARSIGHT, guid);