Updated Copyright year to 2013
[getmangos.git] / src / game / MiscHandler.cpp
blobb347d0cf2eb743f578ae3f4a1e38e71abec7e252
1 /*
2 * Copyright (C) 2005-2013 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 "Database/DatabaseImpl.h"
23 #include "WorldPacket.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "Player.h"
27 #include "World.h"
28 #include "GuildMgr.h"
29 #include "ObjectMgr.h"
30 #include "WorldSession.h"
31 #include "Auth/BigNumber.h"
32 #include "Auth/Sha1.h"
33 #include "UpdateData.h"
34 #include "LootMgr.h"
35 #include "Chat.h"
36 #include "ScriptMgr.h"
37 #include <zlib/zlib.h>
38 #include "ObjectAccessor.h"
39 #include "Object.h"
40 #include "BattleGround/BattleGround.h"
41 #include "OutdoorPvP/OutdoorPvP.h"
42 #include "Guild.h"
43 #include "Pet.h"
44 #include "SocialMgr.h"
45 #include "DBCEnums.h"
47 void WorldSession::HandleRepopRequestOpcode(WorldPacket& recv_data)
49 DEBUG_LOG("WORLD: Recvd CMSG_REPOP_REQUEST Message");
51 recv_data.read_skip<uint8>();
53 if (GetPlayer()->isAlive() || GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
54 return;
56 // the world update order is sessions, players, creatures
57 // the netcode runs in parallel with all of these
58 // creatures can kill players
59 // so if the server is lagging enough the player can
60 // release spirit after he's killed but before he is updated
61 if (GetPlayer()->getDeathState() == JUST_DIED)
63 DEBUG_LOG("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
64 GetPlayer()->KillPlayer();
67 // this is spirit release confirm?
68 GetPlayer()->RemovePet(PET_SAVE_REAGENTS);
69 GetPlayer()->BuildPlayerRepop();
70 GetPlayer()->RepopAtGraveyard();
73 void WorldSession::HandleWhoOpcode(WorldPacket& recv_data)
75 DEBUG_LOG("WORLD: Recvd CMSG_WHO Message");
76 // recv_data.hexlike();
78 uint32 clientcount = 0;
80 uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
81 uint32 zoneids[10]; // 10 is client limit
82 std::string player_name, guild_name;
84 recv_data >> level_min; // maximal player level, default 0
85 recv_data >> level_max; // minimal player level, default 100 (MAX_LEVEL)
86 recv_data >> player_name; // player name, case sensitive...
88 recv_data >> guild_name; // guild name, case sensitive...
90 recv_data >> racemask; // race mask
91 recv_data >> classmask; // class mask
92 recv_data >> zones_count; // zones count, client limit=10 (2.0.10)
94 if (zones_count > 10)
95 return; // can't be received from real client or broken packet
97 for (uint32 i = 0; i < zones_count; ++i)
99 uint32 temp;
100 recv_data >> temp; // zone id, 0 if zone is unknown...
101 zoneids[i] = temp;
102 DEBUG_LOG("Zone %u: %u", i, zoneids[i]);
105 recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10)
107 if (str_count > 4)
108 return; // can't be received from real client or broken packet
110 DEBUG_LOG("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);
112 std::wstring str[4]; // 4 is client limit
113 for (uint32 i = 0; i < str_count; ++i)
115 std::string temp;
116 recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)?
118 if (!Utf8toWStr(temp, str[i]))
119 continue;
121 wstrToLower(str[i]);
123 DEBUG_LOG("String %u: %s", i, temp.c_str());
126 std::wstring wplayer_name;
127 std::wstring wguild_name;
128 if (!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
129 return;
130 wstrToLower(wplayer_name);
131 wstrToLower(wguild_name);
133 // client send in case not set max level value 100 but mangos support 255 max level,
134 // update it to show GMs with characters after 100 level
135 if (level_max >= MAX_LEVEL)
136 level_max = STRONG_MAX_LEVEL;
138 Team team = _player->GetTeam();
139 uint32 security = GetSecurity();
140 bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST);
141 AccountTypes gmLevelInWhoList = (AccountTypes)sWorld.getConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST);
143 WorldPacket data(SMSG_WHO, 50); // guess size
144 data << uint32(clientcount); // clientcount place holder, listed count
145 data << uint32(clientcount); // clientcount place holder, online count
147 // TODO: Guard Player map
148 HashMapHolder<Player>::MapType& m = sObjectAccessor.GetPlayers();
149 for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)
151 Player* pl = itr->second;
153 if (security == SEC_PLAYER)
155 // player can see member of other team only if CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST
156 if (pl->GetTeam() != team && !allowTwoSideWhoList)
157 continue;
159 // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
160 if (pl->GetSession()->GetSecurity() > gmLevelInWhoList)
161 continue;
164 // do not process players which are not in world
165 if (!pl->IsInWorld())
166 continue;
168 // check if target is globally visible for player
169 if (!pl->IsVisibleGloballyFor(_player))
170 continue;
172 // check if target's level is in level range
173 uint32 lvl = pl->getLevel();
174 if (lvl < level_min || lvl > level_max)
175 continue;
177 // check if class matches classmask
178 uint32 class_ = pl->getClass();
179 if (!(classmask & (1 << class_)))
180 continue;
182 // check if race matches racemask
183 uint32 race = pl->getRace();
184 if (!(racemask & (1 << race)))
185 continue;
187 uint32 pzoneid = pl->GetZoneId();
188 uint8 gender = pl->getGender();
190 bool z_show = true;
191 for (uint32 i = 0; i < zones_count; ++i)
193 if (zoneids[i] == pzoneid)
195 z_show = true;
196 break;
199 z_show = false;
201 if (!z_show)
202 continue;
204 std::string pname = pl->GetName();
205 std::wstring wpname;
206 if (!Utf8toWStr(pname, wpname))
207 continue;
208 wstrToLower(wpname);
210 if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
211 continue;
213 std::string gname = sGuildMgr.GetGuildNameById(pl->GetGuildId());
214 std::wstring wgname;
215 if (!Utf8toWStr(gname, wgname))
216 continue;
217 wstrToLower(wgname);
219 if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
220 continue;
222 std::string aname;
223 if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(pzoneid))
224 aname = areaEntry->area_name[GetSessionDbcLocale()];
226 bool s_show = true;
227 for (uint32 i = 0; i < str_count; ++i)
229 if (!str[i].empty())
231 if (wgname.find(str[i]) != std::wstring::npos ||
232 wpname.find(str[i]) != std::wstring::npos ||
233 Utf8FitTo(aname, str[i]))
235 s_show = true;
236 break;
238 s_show = false;
241 if (!s_show)
242 continue;
244 data << pname; // player name
245 data << gname; // guild name
246 data << uint32(lvl); // player level
247 data << uint32(class_); // player class
248 data << uint32(race); // player race
249 data << uint8(gender); // player gender
250 data << uint32(pzoneid); // player zone id
252 // 50 is maximum player count sent to client
253 if ((++clientcount) == 50)
254 break;
257 uint32 count = m.size();
258 data.put(0, clientcount); // insert right count, listed count
259 data.put(4, count > 50 ? count : clientcount); // insert right count, online count
261 SendPacket(&data);
262 DEBUG_LOG("WORLD: Send SMSG_WHO Message");
265 void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recv_data*/)
267 DEBUG_LOG("WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity());
269 if (ObjectGuid lootGuid = GetPlayer()->GetLootGuid())
270 DoLootRelease(lootGuid);
272 // Can not logout if...
273 if (GetPlayer()->isInCombat() || //...is in combat
274 GetPlayer()->duel || //...is in Duel
275 //...is jumping ...is falling
276 GetPlayer()->m_movementInfo.HasMovementFlag(MovementFlags(MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR)))
278 WorldPacket data(SMSG_LOGOUT_RESPONSE, 5);
279 data << uint32(1);
280 data << uint8(0);
281 SendPacket(&data);
282 LogoutRequest(0);
283 return;
286 // instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in mangosd.conf
287 if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->IsTaxiFlying() ||
288 GetSecurity() >= (AccountTypes)sWorld.getConfig(CONFIG_UINT32_INSTANT_LOGOUT))
290 LogoutPlayer(true);
291 return;
294 // not set flags if player can't free move to prevent lost state at logout cancel
295 if (GetPlayer()->CanFreeMove())
297 float height = GetPlayer()->GetTerrain()->GetHeight(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY(), GetPlayer()->GetPositionZ());
298 if ((GetPlayer()->GetPositionZ() < height + 0.1f) && !(GetPlayer()->IsInWater()))
299 GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT);
301 WorldPacket data;
302 GetPlayer()->BuildForceMoveRootPacket(&data, true, 2);
303 SendPacket(&data);
304 GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
307 WorldPacket data(SMSG_LOGOUT_RESPONSE, 5);
308 data << uint32(0);
309 data << uint8(0);
310 SendPacket(&data);
311 LogoutRequest(time(NULL));
314 void WorldSession::HandlePlayerLogoutOpcode(WorldPacket& /*recv_data*/)
316 DEBUG_LOG("WORLD: Recvd CMSG_PLAYER_LOGOUT Message");
319 void WorldSession::HandleLogoutCancelOpcode(WorldPacket& /*recv_data*/)
321 DEBUG_LOG("WORLD: Recvd CMSG_LOGOUT_CANCEL Message");
323 LogoutRequest(0);
325 WorldPacket data(SMSG_LOGOUT_CANCEL_ACK, 0);
326 SendPacket(&data);
328 // not remove flags if can't free move - its not set in Logout request code.
329 if (GetPlayer()->CanFreeMove())
331 //! we can move again
332 GetPlayer()->BuildForceMoveRootPacket(&data, false, 0);
333 SendPacket(&data);
335 //! Stand Up
336 GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND);
338 //! DISABLE_ROTATE
339 GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
342 DEBUG_LOG("WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message");
345 void WorldSession::HandleTogglePvP(WorldPacket& recv_data)
347 // this opcode can be used in two ways: Either set explicit new status or toggle old status
348 if (recv_data.size() == 1)
350 bool newPvPStatus;
351 recv_data >> newPvPStatus;
352 GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus);
353 GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER, !newPvPStatus);
355 else
357 GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP);
358 GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER);
361 if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
363 if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0)
364 GetPlayer()->UpdatePvP(true, true);
366 else
368 if (!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP())
369 GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off
373 void WorldSession::HandleZoneUpdateOpcode(WorldPacket& recv_data)
375 uint32 newZone;
376 recv_data >> newZone;
378 DETAIL_LOG("WORLD: Recvd ZONE_UPDATE: %u", newZone);
380 // use server size data
381 uint32 newzone, newarea;
382 GetPlayer()->GetZoneAndAreaId(newzone, newarea);
383 GetPlayer()->UpdateZone(newzone, newarea);
386 void WorldSession::HandleSetTargetOpcode(WorldPacket& recv_data)
388 // When this packet send?
389 ObjectGuid guid ;
390 recv_data >> guid;
392 _player->SetTargetGuid(guid);
394 // update reputation list if need
395 Unit* unit = ObjectAccessor::GetUnit(*_player, guid); // can select group members at diff maps
396 if (!unit)
397 return;
399 if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction()))
400 _player->GetReputationMgr().SetVisible(factionTemplateEntry);
403 void WorldSession::HandleSetSelectionOpcode(WorldPacket& recv_data)
405 ObjectGuid guid;
406 recv_data >> guid;
408 _player->SetSelectionGuid(guid);
410 // update reputation list if need
411 Unit* unit = ObjectAccessor::GetUnit(*_player, guid); // can select group members at diff maps
412 if (!unit)
413 return;
415 if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction()))
416 _player->GetReputationMgr().SetVisible(factionTemplateEntry);
419 void WorldSession::HandleStandStateChangeOpcode(WorldPacket& recv_data)
421 // DEBUG_LOG( "WORLD: Received CMSG_STANDSTATECHANGE" ); -- too many spam in log at lags/debug stop
422 uint32 animstate;
423 recv_data >> animstate;
425 _player->SetStandState(animstate);
428 void WorldSession::HandleContactListOpcode(WorldPacket& recv_data)
430 DEBUG_LOG("WORLD: Received CMSG_CONTACT_LIST");
431 uint32 unk;
432 recv_data >> unk;
433 DEBUG_LOG("unk value is %u", unk);
434 _player->GetSocial()->SendSocialList();
437 void WorldSession::HandleAddFriendOpcode(WorldPacket& recv_data)
439 DEBUG_LOG("WORLD: Received CMSG_ADD_FRIEND");
441 std::string friendName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
442 std::string friendNote;
444 recv_data >> friendName;
446 recv_data >> friendNote;
448 if (!normalizePlayerName(friendName))
449 return;
451 CharacterDatabase.escape_string(friendName); // prevent SQL injection - normal name don't must changed by this call
453 DEBUG_LOG("WORLD: %s asked to add friend : '%s'",
454 GetPlayer()->GetName(), friendName.c_str());
456 CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race FROM characters WHERE name = '%s'", friendName.c_str());
459 void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult* result, uint32 accountId, std::string friendNote)
461 if (!result)
462 return;
464 uint32 friendLowGuid = (*result)[0].GetUInt32();
465 ObjectGuid friendGuid = ObjectGuid(HIGHGUID_PLAYER, friendLowGuid);
466 Team team = Player::TeamForRace((*result)[1].GetUInt8());
468 delete result;
470 WorldSession* session = sWorld.FindSession(accountId);
471 if (!session || !session->GetPlayer())
472 return;
474 FriendsResult friendResult = FRIEND_NOT_FOUND;
475 if (friendGuid)
477 if (friendGuid == session->GetPlayer()->GetObjectGuid())
478 friendResult = FRIEND_SELF;
479 else if (session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR)
480 friendResult = FRIEND_ENEMY;
481 else if (session->GetPlayer()->GetSocial()->HasFriend(friendGuid))
482 friendResult = FRIEND_ALREADY;
483 else
485 Player* pFriend = ObjectAccessor::FindPlayer(friendGuid);
486 if (pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer()))
487 friendResult = FRIEND_ADDED_ONLINE;
488 else
489 friendResult = FRIEND_ADDED_OFFLINE;
491 if (!session->GetPlayer()->GetSocial()->AddToSocialList(friendGuid, false))
493 friendResult = FRIEND_LIST_FULL;
494 DEBUG_LOG("WORLD: %s's friend list is full.", session->GetPlayer()->GetName());
497 session->GetPlayer()->GetSocial()->SetFriendNote(friendGuid, friendNote);
501 sSocialMgr.SendFriendStatus(session->GetPlayer(), friendResult, friendGuid, false);
503 DEBUG_LOG("WORLD: Sent (SMSG_FRIEND_STATUS)");
506 void WorldSession::HandleDelFriendOpcode(WorldPacket& recv_data)
508 ObjectGuid friendGuid;
510 DEBUG_LOG("WORLD: Received CMSG_DEL_FRIEND");
512 recv_data >> friendGuid;
514 _player->GetSocial()->RemoveFromSocialList(friendGuid, false);
516 sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_REMOVED, friendGuid, false);
518 DEBUG_LOG("WORLD: Sent motd (SMSG_FRIEND_STATUS)");
521 void WorldSession::HandleAddIgnoreOpcode(WorldPacket& recv_data)
523 DEBUG_LOG("WORLD: Received CMSG_ADD_IGNORE");
525 std::string IgnoreName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
527 recv_data >> IgnoreName;
529 if (!normalizePlayerName(IgnoreName))
530 return;
532 CharacterDatabase.escape_string(IgnoreName); // prevent SQL injection - normal name don't must changed by this call
534 DEBUG_LOG("WORLD: %s asked to Ignore: '%s'",
535 GetPlayer()->GetName(), IgnoreName.c_str());
537 CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddIgnoreOpcodeCallBack, GetAccountId(), "SELECT guid FROM characters WHERE name = '%s'", IgnoreName.c_str());
540 void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult* result, uint32 accountId)
542 if (!result)
543 return;
545 uint32 ignoreLowGuid = (*result)[0].GetUInt32();
546 ObjectGuid ignoreGuid = ObjectGuid(HIGHGUID_PLAYER, ignoreLowGuid);
548 delete result;
550 WorldSession* session = sWorld.FindSession(accountId);
551 if (!session || !session->GetPlayer())
552 return;
554 FriendsResult ignoreResult = FRIEND_IGNORE_NOT_FOUND;
555 if (ignoreGuid)
557 if (ignoreGuid == session->GetPlayer()->GetObjectGuid())
558 ignoreResult = FRIEND_IGNORE_SELF;
559 else if (session->GetPlayer()->GetSocial()->HasIgnore(ignoreGuid))
560 ignoreResult = FRIEND_IGNORE_ALREADY;
561 else
563 ignoreResult = FRIEND_IGNORE_ADDED;
565 // ignore list full
566 if (!session->GetPlayer()->GetSocial()->AddToSocialList(ignoreGuid, true))
567 ignoreResult = FRIEND_IGNORE_FULL;
571 sSocialMgr.SendFriendStatus(session->GetPlayer(), ignoreResult, ignoreGuid, false);
573 DEBUG_LOG("WORLD: Sent (SMSG_FRIEND_STATUS)");
576 void WorldSession::HandleDelIgnoreOpcode(WorldPacket& recv_data)
578 ObjectGuid ignoreGuid;
580 DEBUG_LOG("WORLD: Received CMSG_DEL_IGNORE");
582 recv_data >> ignoreGuid;
584 _player->GetSocial()->RemoveFromSocialList(ignoreGuid, true);
586 sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, ignoreGuid, false);
588 DEBUG_LOG("WORLD: Sent motd (SMSG_FRIEND_STATUS)");
591 void WorldSession::HandleSetContactNotesOpcode(WorldPacket& recv_data)
593 DEBUG_LOG("CMSG_SET_CONTACT_NOTES");
594 ObjectGuid guid;
595 std::string note;
596 recv_data >> guid >> note;
597 _player->GetSocial()->SetFriendNote(guid, note);
600 void WorldSession::HandleBugOpcode(WorldPacket& recv_data)
602 uint32 suggestion, contentlen, typelen;
603 std::string content, type;
605 recv_data >> suggestion >> contentlen >> content;
607 recv_data >> typelen >> type;
609 if (suggestion == 0)
610 DEBUG_LOG("WORLD: Received CMSG_BUG [Bug Report]");
611 else
612 DEBUG_LOG("WORLD: Received CMSG_BUG [Suggestion]");
614 DEBUG_LOG("%s", type.c_str());
615 DEBUG_LOG("%s", content.c_str());
617 CharacterDatabase.escape_string(type);
618 CharacterDatabase.escape_string(content);
619 CharacterDatabase.PExecute("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type.c_str(), content.c_str());
622 void WorldSession::HandleReclaimCorpseOpcode(WorldPacket& recv_data)
624 DETAIL_LOG("WORLD: Received CMSG_RECLAIM_CORPSE");
626 ObjectGuid guid;
627 recv_data >> guid;
629 if (GetPlayer()->isAlive())
630 return;
632 // do not allow corpse reclaim in arena
633 if (GetPlayer()->InArena())
634 return;
636 // body not released yet
637 if (!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
638 return;
640 Corpse* corpse = GetPlayer()->GetCorpse();
642 if (!corpse)
643 return;
645 // prevent resurrect before 30-sec delay after body release not finished
646 if (corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType() == CORPSE_RESURRECTABLE_PVP) > time(NULL))
647 return;
649 if (!corpse->IsWithinDistInMap(GetPlayer(), CORPSE_RECLAIM_RADIUS, true))
650 return;
652 // resurrect
653 GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f : 0.5f);
655 // spawn bones
656 GetPlayer()->SpawnCorpseBones();
659 void WorldSession::HandleResurrectResponseOpcode(WorldPacket& recv_data)
661 DETAIL_LOG("WORLD: Received CMSG_RESURRECT_RESPONSE");
663 ObjectGuid guid;
664 uint8 status;
665 recv_data >> guid;
666 recv_data >> status;
668 if (GetPlayer()->isAlive())
669 return;
671 if (status == 0)
673 GetPlayer()->clearResurrectRequestData(); // reject
674 return;
677 if (!GetPlayer()->isRessurectRequestedBy(guid))
678 return;
680 GetPlayer()->ResurectUsingRequestData(); // will call spawncorpsebones
683 void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
685 DEBUG_LOG("WORLD: Received CMSG_AREATRIGGER");
687 uint32 Trigger_ID;
689 recv_data >> Trigger_ID;
690 DEBUG_LOG("Trigger ID: %u", Trigger_ID);
691 Player* player = GetPlayer();
693 if (player->IsTaxiFlying())
695 DEBUG_LOG("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID);
696 return;
699 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
700 if (!atEntry)
702 DEBUG_LOG("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID);
703 return;
706 // delta is safe radius
707 const float delta = 5.0f;
709 // check if player in the range of areatrigger
710 if (!IsPointInAreaTriggerZone(atEntry, player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), delta))
712 DEBUG_LOG("Player '%s' (GUID: %u) too far, ignore Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID);
713 return;
716 if (sScriptMgr.OnAreaTrigger(player, atEntry))
717 return;
719 uint32 quest_id = sObjectMgr.GetQuestForAreaTrigger(Trigger_ID);
720 if (quest_id && player->isAlive() && player->IsActiveQuest(quest_id))
722 Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id);
723 if (pQuest)
725 if (player->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE)
726 player->AreaExploredOrEventHappens(quest_id);
730 // enter to tavern, not overwrite city rest
731 if (sObjectMgr.IsTavernAreaTrigger(Trigger_ID))
733 // set resting flag we are in the inn
734 if (player->GetRestType() != REST_TYPE_IN_CITY)
735 player->SetRestType(REST_TYPE_IN_TAVERN, Trigger_ID);
736 return;
739 if (BattleGround* bg = player->GetBattleGround())
741 bg->HandleAreaTrigger(player, Trigger_ID);
742 return;
744 else if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(player->GetCachedZoneId()))
746 if (outdoorPvP->HandleAreaTrigger(player, Trigger_ID))
747 return;
750 // NULL if all values default (non teleport trigger)
751 AreaTrigger const* at = sObjectMgr.GetAreaTrigger(Trigger_ID);
752 if (!at)
753 return;
755 MapEntry const* targetMapEntry = sMapStore.LookupEntry(at->target_mapId);
756 if (!targetMapEntry)
757 return;
759 // ghost resurrected at enter attempt to dungeon with corpse (including fail enter cases)
760 if (!player->isAlive() && targetMapEntry->IsDungeon())
762 int32 corpseMapId = 0;
763 if (Corpse* corpse = player->GetCorpse())
764 corpseMapId = corpse->GetMapId();
766 // check back way from corpse to entrance
767 uint32 instance_map = corpseMapId;
770 // most often fast case
771 if (instance_map == targetMapEntry->MapID)
772 break;
774 InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(instance_map);
775 instance_map = instance ? instance->parent : 0;
777 while (instance_map);
779 // corpse not in dungeon or some linked deep dungeons
780 if (!instance_map)
782 WorldPacket data(SMSG_AREA_TRIGGER_NO_CORPSE);
783 player->GetSession()->SendPacket(&data);
784 return;
787 // need find areatrigger to inner dungeon for landing point
788 if (at->target_mapId != corpseMapId)
790 if (AreaTrigger const* corpseAt = sObjectMgr.GetMapEntranceTrigger(corpseMapId))
792 at = corpseAt;
793 targetMapEntry = sMapStore.LookupEntry(at->target_mapId);
797 // now we can resurrect player, and then check teleport requirements
798 player->ResurrectPlayer(0.5f);
799 player->SpawnCorpseBones();
802 // teleport player (trigger requirement will be checked on TeleportTo)
803 player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT, at);
806 void WorldSession::HandleUpdateAccountData(WorldPacket& recv_data)
808 DETAIL_LOG("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA");
810 uint32 type, timestamp, decompressedSize;
811 recv_data >> type >> timestamp >> decompressedSize;
813 DEBUG_LOG("UAD: type %u, time %u, decompressedSize %u", type, timestamp, decompressedSize);
815 if (type > NUM_ACCOUNT_DATA_TYPES)
816 return;
818 if (decompressedSize == 0) // erase
820 SetAccountData(AccountDataType(type), 0, "");
822 WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4 + 4);
823 data << uint32(type);
824 data << uint32(0);
825 SendPacket(&data);
827 return;
830 if (decompressedSize > 0xFFFF)
832 recv_data.rpos(recv_data.wpos()); // unnneded warning spam in this case
833 sLog.outError("UAD: Account data packet too big, size %u", decompressedSize);
834 return;
837 ByteBuffer dest;
838 dest.resize(decompressedSize);
840 uLongf realSize = decompressedSize;
841 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)
843 recv_data.rpos(recv_data.wpos()); // unneded warning spam in this case
844 sLog.outError("UAD: Failed to decompress account data");
845 return;
848 recv_data.rpos(recv_data.wpos()); // uncompress read (recv_data.size() - recv_data.rpos())
850 std::string adata;
851 dest >> adata;
853 SetAccountData(AccountDataType(type), timestamp, adata);
855 WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4 + 4);
856 data << uint32(type);
857 data << uint32(0);
858 SendPacket(&data);
861 void WorldSession::HandleRequestAccountData(WorldPacket& recv_data)
863 DETAIL_LOG("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA");
865 uint32 type;
866 recv_data >> type;
868 DEBUG_LOG("RAD: type %u", type);
870 if (type > NUM_ACCOUNT_DATA_TYPES)
871 return;
873 AccountData* adata = GetAccountData(AccountDataType(type));
875 uint32 size = adata->Data.size();
877 uLongf destSize = compressBound(size);
879 ByteBuffer dest;
880 dest.resize(destSize);
882 if (size && compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK)
884 DEBUG_LOG("RAD: Failed to compress account data");
885 return;
888 dest.resize(destSize);
890 WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA, 8 + 4 + 4 + 4 + destSize);
891 data << (_player ? _player->GetObjectGuid() : ObjectGuid());// player guid
892 data << uint32(type); // type (0-7)
893 data << uint32(adata->Time); // unix time
894 data << uint32(size); // decompressed length
895 data.append(dest); // compressed data
896 SendPacket(&data);
899 void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
901 DEBUG_LOG("WORLD: Received CMSG_SET_ACTION_BUTTON");
902 uint8 button;
903 uint32 packetData;
904 recv_data >> button >> packetData;
906 uint32 action = ACTION_BUTTON_ACTION(packetData);
907 uint8 type = ACTION_BUTTON_TYPE(packetData);
909 DETAIL_LOG("BUTTON: %u ACTION: %u TYPE: %u", button, action, type);
910 if (!packetData)
912 DETAIL_LOG("MISC: Remove action from button %u", button);
913 GetPlayer()->removeActionButton(GetPlayer()->GetActiveSpec(), button);
915 else
917 switch (type)
919 case ACTION_BUTTON_MACRO:
920 case ACTION_BUTTON_CMACRO:
921 DETAIL_LOG("MISC: Added Macro %u into button %u", action, button);
922 break;
923 case ACTION_BUTTON_EQSET:
924 DETAIL_LOG("MISC: Added EquipmentSet %u into button %u", action, button);
925 break;
926 case ACTION_BUTTON_SPELL:
927 DETAIL_LOG("MISC: Added Spell %u into button %u", action, button);
928 break;
929 case ACTION_BUTTON_ITEM:
930 DETAIL_LOG("MISC: Added Item %u into button %u", action, button);
931 break;
932 default:
933 sLog.outError("MISC: Unknown action button type %u for action %u into button %u", type, action, button);
934 return;
936 GetPlayer()->addActionButton(GetPlayer()->m_activeSpec, button, action, type);
940 void WorldSession::HandleCompleteCinematic(WorldPacket& /*recv_data*/)
942 DEBUG_LOG("WORLD: Player is watching cinema");
945 void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recv_data*/)
947 DEBUG_LOG("WORLD: Which movie to play");
950 void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recv_data)
952 /* WorldSession::Update( WorldTimer::getMSTime() );*/
953 DEBUG_LOG("WORLD: Time Lag/Synchronization Resent/Update");
955 ObjectGuid guid;
957 recv_data >> Unused<uint32>();
958 recv_data.ReadGuidMask<5, 1, 3, 7, 6, 0, 4, 2>(guid);
959 recv_data.ReadGuidBytes<7, 1, 2, 4, 3, 6, 0, 5>(guid);
962 ObjectGuid guid;
963 uint32 time_skipped;
964 recv_data >> guid;
965 recv_data >> time_skipped;
966 DEBUG_LOG( "WORLD: CMSG_MOVE_TIME_SKIPPED" );
968 /// TODO
969 must be need use in mangos
970 We substract server Lags to move time ( AntiLags )
971 for exmaple
972 GetPlayer()->ModifyLastMoveTime( -int32(time_skipped) );
976 void WorldSession::HandleFeatherFallAck(WorldPacket& recv_data)
978 DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
980 // not used
981 recv_data.rfinish(); // prevent warnings spam
983 bitsream packet
987 void WorldSession::HandleMoveUnRootAck(WorldPacket& recv_data)
989 // not used
990 recv_data.rfinish(); // prevent warnings spam
992 bitsream packet
996 void WorldSession::HandleMoveRootAck(WorldPacket& recv_data)
998 // not used
999 recv_data.rfinish(); // prevent warnings spam
1001 bitsream packet
1005 void WorldSession::HandleSetActionBarTogglesOpcode(WorldPacket& recv_data)
1007 uint8 ActionBar;
1009 recv_data >> ActionBar;
1011 if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED)
1013 if (ActionBar != 0)
1014 sLog.outError("WorldSession::HandleSetActionBarToggles in not logged state with value: %u, ignored", uint32(ActionBar));
1015 return;
1018 GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar);
1021 void WorldSession::HandleWardenDataOpcode(WorldPacket& recv_data)
1023 recv_data.read_skip<uint8>();
1025 uint8 tmp;
1026 recv_data >> tmp;
1027 DEBUG_LOG("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u", tmp);
1031 void WorldSession::HandlePlayedTime(WorldPacket& recv_data)
1033 uint8 unk1;
1034 recv_data >> unk1; // 0 or 1 expected
1036 WorldPacket data(SMSG_PLAYED_TIME, 4 + 4 + 1);
1037 data << uint32(_player->GetTotalPlayedTime());
1038 data << uint32(_player->GetLevelPlayedTime());
1039 data << uint8(unk1); // 0 - will not show in chat frame
1040 SendPacket(&data);
1043 void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
1045 ObjectGuid guid;
1046 recv_data >> guid;
1047 DEBUG_LOG("Inspected guid is %s", guid.GetString().c_str());
1049 _player->SetSelectionGuid(guid);
1051 Player* plr = sObjectMgr.GetPlayer(guid);
1052 if (!plr) // wrong player
1053 return;
1055 WorldPacket data(SMSG_INSPECT_RESULTS, 50);
1056 data << plr->GetObjectGuid();
1058 if (sWorld.getConfig(CONFIG_BOOL_TALENTS_INSPECTING) || _player->isGameMaster())
1059 plr->BuildPlayerTalentsInfoData(&data);
1060 else
1062 data << uint32(0); // unspentTalentPoints
1063 data << uint8(0); // talentGroupCount
1064 data << uint8(0); // talentGroupIndex
1067 plr->BuildEnchantmentsInfoData(&data);
1068 if (Guild* guild = sGuildMgr.GetGuildById(plr->GetGuildId()))
1070 data << guild->GetObjectGuid();
1071 data << uint32(guild->GetLevel());
1072 data << uint64(0/*guild->GetXP()*/);
1073 data << uint32(guild->GetMemberSize()); // number of members
1076 SendPacket(&data);
1079 void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data)
1081 ObjectGuid guid;
1082 recv_data.ReadGuidMask<1, 5, 7, 3, 2, 4, 0, 6>(guid);
1083 recv_data.ReadGuidBytes<4, 7, 0, 5, 1, 6, 2, 3>(guid);
1085 Player* player = sObjectMgr.GetPlayer(guid);
1086 if (!player)
1088 sLog.outError("InspectHonorStats: WTF, player not found...");
1089 return;
1092 WorldPacket data(SMSG_INSPECT_HONOR_STATS, 18);
1093 data.WriteGuidMask<4, 3, 6, 2, 5, 0, 7, 1>(player->GetObjectGuid());
1094 data << uint8(0); // rank
1095 data << uint16(player->GetUInt16Value(PLAYER_FIELD_KILLS, 1)); // yesterday kills
1096 data << uint16(player->GetUInt16Value(PLAYER_FIELD_KILLS, 0)); // today kills
1097 data.WriteGuidBytes<2, 0, 6, 3, 4, 1, 5>(player->GetObjectGuid());
1098 data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS));
1099 data.WriteGuidBytes<7>(player->GetObjectGuid());
1101 SendPacket(&data);
1104 void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data)
1106 // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180
1107 // Received opcode CMSG_WORLD_TELEPORT
1108 // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593
1110 uint32 time;
1111 uint32 mapid;
1112 float PositionX;
1113 float PositionY;
1114 float PositionZ;
1115 float Orientation;
1117 recv_data >> time; // time in m.sec.
1118 recv_data >> mapid;
1119 recv_data >> PositionX;
1120 recv_data >> PositionY;
1121 recv_data >> PositionZ;
1122 recv_data >> Orientation; // o (3.141593 = 180 degrees)
1124 // DEBUG_LOG("Received opcode CMSG_WORLD_TELEPORT");
1126 if (GetPlayer()->IsTaxiFlying())
1128 DEBUG_LOG("Player '%s' (GUID: %u) in flight, ignore worldport command.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
1129 return;
1132 DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time / 1000, mapid, PositionX, PositionY, PositionZ, Orientation);
1134 if (GetSecurity() >= SEC_ADMINISTRATOR)
1135 GetPlayer()->TeleportTo(mapid, PositionX, PositionY, PositionZ, Orientation);
1136 else
1137 SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
1138 DEBUG_LOG("Received worldport command from player %s", GetPlayer()->GetName());
1141 void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
1143 DEBUG_LOG("Received opcode CMSG_WHOIS");
1144 std::string charname;
1145 recv_data >> charname;
1147 if (GetSecurity() < SEC_ADMINISTRATOR)
1149 SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
1150 return;
1153 if (charname.empty() || !normalizePlayerName(charname))
1155 SendNotification(LANG_NEED_CHARACTER_NAME);
1156 return;
1159 Player* plr = sObjectMgr.GetPlayer(charname.c_str());
1161 if (!plr)
1163 SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str());
1164 return;
1167 uint32 accid = plr->GetSession()->GetAccountId();
1169 QueryResult* result = LoginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
1170 if (!result)
1172 SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str());
1173 return;
1176 Field* fields = result->Fetch();
1177 std::string acc = fields[0].GetCppString();
1178 if (acc.empty())
1179 acc = "Unknown";
1180 std::string email = fields[1].GetCppString();
1181 if (email.empty())
1182 email = "Unknown";
1183 std::string lastip = fields[2].GetCppString();
1184 if (lastip.empty())
1185 lastip = "Unknown";
1187 std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip;
1189 WorldPacket data(SMSG_WHOIS, msg.size() + 1);
1190 data << msg;
1191 _player->GetSession()->SendPacket(&data);
1193 delete result;
1195 DEBUG_LOG("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str());
1198 void WorldSession::HandleComplainOpcode(WorldPacket& recv_data)
1200 DEBUG_LOG("WORLD: CMSG_COMPLAIN");
1201 recv_data.hexlike();
1203 uint8 spam_type; // 0 - mail, 1 - chat
1204 ObjectGuid spammerGuid;
1205 uint32 unk1 = 0;
1206 uint32 unk2 = 0;
1207 uint32 unk3 = 0;
1208 uint32 unk4 = 0;
1209 std::string description = "";
1210 recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat)
1211 recv_data >> spammerGuid; // player guid
1212 switch (spam_type)
1214 case 0:
1215 recv_data >> unk1; // const 0
1216 recv_data >> unk2; // probably mail id
1217 recv_data >> unk3; // const 0
1218 break;
1219 case 1:
1220 recv_data >> unk1; // probably language
1221 recv_data >> unk2; // message type?
1222 recv_data >> unk3; // probably channel id
1223 recv_data >> unk4; // unk random value
1224 recv_data >> description; // spam description string (messagetype, channel name, player name, message)
1225 break;
1228 // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam.
1229 // if it's mail spam - ALL mails from this spammer automatically removed by client
1231 // Complaint Received message
1232 WorldPacket data(SMSG_COMPLAIN_RESULT, 1);
1233 data << uint8(0);
1234 SendPacket(&data);
1236 DEBUG_LOG("REPORT SPAM: type %u, spammer %s, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, spammerGuid.GetString().c_str(), unk1, unk2, unk3, unk4, description.c_str());
1239 void WorldSession::HandleRealmSplitOpcode(WorldPacket& recv_data)
1241 DEBUG_LOG("CMSG_REALM_SPLIT");
1243 uint32 unk;
1244 std::string split_date = "01/01/01";
1245 recv_data >> unk;
1247 WorldPacket data(SMSG_REALM_SPLIT, 4 + 4 + split_date.size() + 1);
1248 data << unk;
1249 data << uint32(0x00000000); // realm split state
1250 // split states:
1251 // 0x0 realm normal
1252 // 0x1 realm split
1253 // 0x2 realm split pending
1254 data << split_date;
1255 SendPacket(&data);
1256 // DEBUG_LOG("response sent %u", unk);
1259 void WorldSession::HandleFarSightOpcode(WorldPacket& recv_data)
1261 DEBUG_LOG("WORLD: CMSG_FAR_SIGHT");
1262 // recv_data.hexlike();
1264 uint8 op;
1265 recv_data >> op;
1267 WorldObject* obj = _player->GetMap()->GetWorldObject(_player->GetFarSightGuid());
1268 if (!obj)
1269 return;
1271 switch (op)
1273 case 0:
1274 DEBUG_LOG("Removed FarSight from %s", _player->GetGuidStr().c_str());
1275 _player->GetCamera().ResetView(false);
1276 break;
1277 case 1:
1278 DEBUG_LOG("Added FarSight %s to %s", _player->GetFarSightGuid().GetString().c_str(), _player->GetGuidStr().c_str());
1279 _player->GetCamera().SetView(obj, false);
1280 break;
1284 void WorldSession::HandleSetTitleOpcode(WorldPacket& recv_data)
1286 DEBUG_LOG("CMSG_SET_TITLE");
1288 int32 title;
1289 recv_data >> title;
1291 // -1 at none
1292 if (title > 0 && title < MAX_TITLE_INDEX)
1294 if (!GetPlayer()->HasTitle(title))
1295 return;
1297 else
1298 title = 0;
1300 GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title);
1303 void WorldSession::HandleTimeSyncResp(WorldPacket& recv_data)
1305 DEBUG_LOG("CMSG_TIME_SYNC_RESP");
1307 uint32 counter, clientTicks;
1308 recv_data >> counter >> clientTicks;
1310 if (counter != _player->m_timeSyncCounter - 1)
1311 DEBUG_LOG("Wrong time sync counter from player %s (cheater?)", _player->GetName());
1313 DEBUG_LOG("Time sync received: counter %u, client ticks %u, time since last sync %u", counter, clientTicks, clientTicks - _player->m_timeSyncClient);
1315 uint32 ourTicks = clientTicks + (WorldTimer::getMSTime() - _player->m_timeSyncServer);
1317 // diff should be small
1318 DEBUG_LOG("Our ticks: %u, diff %u, latency %u", ourTicks, ourTicks - clientTicks, GetLatency());
1320 _player->m_timeSyncClient = clientTicks;
1323 void WorldSession::HandleResetInstancesOpcode(WorldPacket& /*recv_data*/)
1325 DEBUG_LOG("WORLD: CMSG_RESET_INSTANCES");
1327 if (Group* pGroup = _player->GetGroup())
1329 if (pGroup->IsLeader(_player->GetObjectGuid()))
1330 pGroup->ResetInstances(INSTANCE_RESET_ALL, false, _player);
1332 else
1333 _player->ResetInstances(INSTANCE_RESET_ALL, false);
1336 void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket& recv_data)
1338 DEBUG_LOG("MSG_SET_DUNGEON_DIFFICULTY");
1340 uint32 mode;
1341 recv_data >> mode;
1343 if (mode >= MAX_DUNGEON_DIFFICULTY)
1345 sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
1346 return;
1349 if (Difficulty(mode) == _player->GetDungeonDifficulty())
1350 return;
1352 // cannot reset while in an instance
1353 Map* map = _player->GetMap();
1354 if (map && map->IsDungeon())
1356 sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow());
1357 return;
1360 // Exception to set mode to normal for low-level players
1361 if (_player->getLevel() < LEVELREQUIREMENT_HEROIC && mode > REGULAR_DIFFICULTY)
1362 return;
1364 if (Group* pGroup = _player->GetGroup())
1366 if (pGroup->IsLeader(_player->GetObjectGuid()))
1368 // the difficulty is set even if the instances can't be reset
1369 //_player->SendDungeonDifficulty(true);
1370 pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player);
1371 pGroup->SetDungeonDifficulty(Difficulty(mode));
1374 else
1376 _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false);
1377 _player->SetDungeonDifficulty(Difficulty(mode));
1381 void WorldSession::HandleSetRaidDifficultyOpcode(WorldPacket& recv_data)
1383 DEBUG_LOG("MSG_SET_RAID_DIFFICULTY");
1385 uint32 mode;
1386 recv_data >> mode;
1388 if (mode >= MAX_RAID_DIFFICULTY)
1390 sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
1391 return;
1394 if (Difficulty(mode) == _player->GetRaidDifficulty())
1395 return;
1397 // cannot reset while in an instance
1398 Map* map = _player->GetMap();
1399 if (map && map->IsDungeon())
1401 sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow());
1402 return;
1405 // Exception to set mode to normal for low-level players
1406 if (_player->getLevel() < LEVELREQUIREMENT_HEROIC && mode > REGULAR_DIFFICULTY)
1407 return;
1409 if (Group* pGroup = _player->GetGroup())
1411 if (pGroup->IsLeader(_player->GetObjectGuid()))
1413 // the difficulty is set even if the instances can't be reset
1414 _player->SendDungeonDifficulty(true);
1415 pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, _player);
1416 pGroup->SetRaidDifficulty(Difficulty(mode));
1419 else
1421 _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true);
1422 _player->SetRaidDifficulty(Difficulty(mode));
1426 void WorldSession::HandleCancelMountAuraOpcode(WorldPacket& /*recv_data*/)
1428 DEBUG_LOG("WORLD: CMSG_CANCEL_MOUNT_AURA");
1430 // If player is not mounted, so go out :)
1431 if (!_player->IsMounted()) // not blizz like; no any messages on blizz
1433 ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED);
1434 return;
1437 if (_player->IsTaxiFlying()) // not blizz like; no any messages on blizz
1439 ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT);
1440 return;
1443 _player->Unmount(_player->HasAuraType(SPELL_AURA_MOUNTED));
1444 _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
1447 void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recv_data)
1449 // fly mode on/off
1450 DEBUG_LOG("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
1452 MovementInfo movementInfo;
1453 recv_data >> movementInfo;
1455 if (_player->GetMover()->GetObjectGuid() != movementInfo.GetGuid())
1457 DEBUG_LOG("WorldSession::HandleMoveSetCanFlyAckOpcode: player %s, mover %s, received %s, ignored",
1458 _player->GetGuidStr().c_str(), _player->GetMover()->GetGuidStr().c_str(), movementInfo.GetGuid().GetString().c_str());
1459 return;
1462 _player->GetMover()->m_movementInfo.SetMovementFlags(movementInfo.GetMovementFlags());
1465 void WorldSession::HandleRequestPetInfoOpcode(WorldPacket& /*recv_data */)
1468 DEBUG_LOG("WORLD: CMSG_REQUEST_PET_INFO");
1469 recv_data.hexlike();
1473 void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket& recv_data)
1475 uint8 mode;
1476 recv_data >> mode;
1478 DEBUG_LOG("Client used \"/timetest %d\" command", mode);
1481 void WorldSession::HandleQueryInspectAchievementsOpcode(WorldPacket& recv_data)
1483 ObjectGuid guid;
1485 recv_data >> guid.ReadAsPacked();
1487 if (Player* player = sObjectMgr.GetPlayer(guid))
1488 player->GetAchievementMgr().SendRespondInspectAchievements(_player);
1491 void WorldSession::HandleUITimeRequestOpcode(WorldPacket& /*recv_data*/)
1493 // empty opcode
1494 DEBUG_LOG("WORLD: SMSG_UI_TIME");
1496 WorldPacket data(SMSG_UI_TIME, 4);
1497 data << uint32(time(NULL));
1498 SendPacket(&data);
1501 void WorldSession::HandleReadyForAccountDataTimesOpcode(WorldPacket& /*recv_data*/)
1503 // empty opcode
1504 DEBUG_LOG("WORLD: CMSG_READY_FOR_ACCOUNT_DATA_TIMES");
1506 SendAccountDataTimes(GLOBAL_CACHE_MASK);
1509 void WorldSession::HandleHearthandResurrect(WorldPacket& /*recv_data*/)
1511 DEBUG_LOG("WORLD: CMSG_HEARTH_AND_RESURRECT");
1513 AreaTableEntry const* atEntry = sAreaStore.LookupEntry(_player->GetAreaId());
1514 if (!atEntry || !(atEntry->flags & AREA_FLAG_CAN_HEARTH_AND_RES))
1515 return;
1517 // Can't use in flight
1518 if (_player->IsTaxiFlying())
1519 return;
1521 // Send Everytime
1522 _player->BuildPlayerRepop();
1523 _player->ResurrectPlayer(100);
1524 _player->TeleportToHomebind();