diff options
Diffstat (limited to 'src/server/game')
233 files changed, 35984 insertions, 18943 deletions
diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp index 245a47dbe64..27ecc2716f3 100644 --- a/src/server/game/AI/CoreAI/TotemAI.cpp +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -95,15 +95,4 @@ void TotemAI::UpdateAI(uint32 /*diff*/) void TotemAI::AttackStart(Unit* /*victim*/) { - // Sentry totem sends ping on attack - if (me->GetEntry() == SENTRY_TOTEM_ENTRY) - if (Unit* owner = me->GetOwner()) - if (Player* player = owner->ToPlayer()) - { - WorldPacket data(MSG_MINIMAP_PING, (8+4+4)); - data << me->GetGUID(); - data << me->GetPositionX(); - data << me->GetPositionY(); - player->SendDirectMessage(&data); - } } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 06820b03218..614f5826824 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -234,7 +234,7 @@ SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mec continue; //Continue if we don't have the mana to actually cast this spell - if (tempSpell->ManaCost > me->GetPower(Powers(tempSpell->PowerType))) + if (tempSpell->ManaCost > (uint32)me->GetPower(Powers(tempSpell->PowerType))) continue; //Check if the spell meets our range requirements @@ -586,6 +586,20 @@ void BossAI::UpdateAI(uint32 diff) DoMeleeAttackIfReady(); } +void BossAI::_DespawnAtEvade() +{ + uint32 corpseDelay = me->GetCorpseDelay(); + uint32 respawnDelay = me->GetRespawnDelay(); + + me->SetCorpseDelay(1); + me->SetRespawnDelay(29); + + me->DespawnOrUnsummon(); + + me->SetCorpseDelay(corpseDelay); + me->SetRespawnDelay(respawnDelay); +} + // WorldBossAI - for non-instanced bosses WorldBossAI::WorldBossAI(Creature* creature) : diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index c9f7f342183..e03bbd8c6a2 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -360,6 +360,7 @@ class BossAI : public ScriptedAI void _EnterCombat(); void _JustDied(); void _JustReachedHome() { me->setActive(false); } + void _DespawnAtEvade(); bool CheckInRoom() { diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 02298684584..d4b41f529a9 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1045,7 +1045,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u delete targets; break; } - case SMART_ACTION_SET_INGAME_PHASE_MASK: + case SMART_ACTION_SET_INGAME_PHASE_ID: { ObjectList* targets = GetTargets(e, unit); @@ -1053,12 +1053,23 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetPhaseMask(e.action.ingamePhaseMask.mask, true); - else if (IsGameObject(*itr)) - (*itr)->ToGameObject()->SetPhaseMask(e.action.ingamePhaseMask.mask, true); - } + (*itr)->SetInPhase(e.action.ingamePhaseId.id, true, e.action.ingamePhaseId.apply == 1); + + delete targets; + break; + } + case SMART_ACTION_SET_INGAME_PHASE_GROUP: + { + ObjectList* targets = GetTargets(e, unit); + + if (!targets) + break; + + std::set<uint32> const& phases = GetPhasesForGroup(e.action.ingamePhaseGroup.groupId); + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + for (auto phase : phases) + (*itr)->SetInPhase(phase, true, e.action.ingamePhaseGroup.apply == 1); delete targets; break; @@ -1392,8 +1403,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; if (e.GetTargetType() == SMART_TARGET_SELF) - me->SetFacingTo((me->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && me->GetTransGUID() ? - me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation()); + me->SetFacingTo((me->GetTransport() ? me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation()); else if (e.GetTargetType() == SMART_TARGET_POSITION) me->SetFacingTo(e.target.o); else if (ObjectList* targets = GetTargets(e, unit)) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 2e8453904a1..af24298c60d 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -1008,6 +1008,44 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) } break; } + case SMART_ACTION_SET_INGAME_PHASE_ID: + { + uint32 phaseId = e.action.ingamePhaseId.id; + uint32 apply = e.action.ingamePhaseId.apply; + + if (apply != 0 && apply != 1) + { + TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid apply value %u (Should be 0 or 1) for creature %u, skipped", apply, e.entryOrGuid); + return false; + } + + PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId); + if (!phase) + { + TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid phaseid %u for creature %u, skipped", phaseId, e.entryOrGuid); + return false; + } + break; + } + case SMART_ACTION_SET_INGAME_PHASE_GROUP: + { + uint32 phaseGroup = e.action.ingamePhaseGroup.groupId; + uint32 apply = e.action.ingamePhaseGroup.apply; + + if (apply != 0 && apply != 1) + { + TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid apply value %u (Should be 0 or 1) for creature %u, skipped", apply, e.entryOrGuid); + return false; + } + + PhaseGroupEntry const* phase = sPhaseGroupStore.LookupEntry(phaseGroup); + if (!phase) + { + TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id %u for creature %u, skipped", phaseGroup, e.entryOrGuid); + return false; + } + break; + } case SMART_ACTION_FOLLOW: case SMART_ACTION_SET_ORIENTATION: case SMART_ACTION_STORE_TARGET_LIST: @@ -1037,7 +1075,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_SET_RUN: case SMART_ACTION_SET_SWIM: case SMART_ACTION_FORCE_DESPAWN: - case SMART_ACTION_SET_INGAME_PHASE_MASK: case SMART_ACTION_SET_UNIT_FLAG: case SMART_ACTION_REMOVE_UNIT_FLAG: case SMART_ACTION_PLAYMOVIE: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index d4afba54498..f09e16268c1 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -23,6 +23,7 @@ #include "CreatureAI.h" #include "Unit.h" #include "Spell.h" +#include "DB2Stores.h" //#include "SmartScript.h" //#include "SmartAI.h" @@ -432,7 +433,7 @@ enum SMART_ACTION SMART_ACTION_THREAT_SINGLE_PCT = 13, // Threat% SMART_ACTION_THREAT_ALL_PCT = 14, // Threat% SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS = 15, // QuestID - SMART_ACTION_UNUSED_16 = 16, // UNUSED + SMART_ACTION_SET_INGAME_PHASE_GROUP = 16, // phaseGroupId, apply SMART_ACTION_SET_EMOTE_STATE = 17, // emoteID SMART_ACTION_SET_UNIT_FLAG = 18, // Flags (may be more than one field OR'd together), Target SMART_ACTION_REMOVE_UNIT_FLAG = 19, // Flags (may be more than one field OR'd together), Target @@ -460,7 +461,7 @@ enum SMART_ACTION SMART_ACTION_FORCE_DESPAWN = 41, // timer SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue(+pct, -flat) SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to dismount) - SMART_ACTION_SET_INGAME_PHASE_MASK = 44, // mask + SMART_ACTION_SET_INGAME_PHASE_ID = 44, // PhaseId, apply SMART_ACTION_SET_DATA = 45, // Field, Data (only creature @todo) SMART_ACTION_MOVE_FORWARD = 46, // distance SMART_ACTION_SET_VISIBILITY = 47, // on/off @@ -727,8 +728,15 @@ struct SmartAction struct { - uint32 mask; - } ingamePhaseMask; + uint32 id; + uint32 apply; + } ingamePhaseId; + + struct + { + uint32 groupId; + uint32 apply; + } ingamePhaseGroup; struct { diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index ff30fe7ba35..c7437909f05 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -33,17 +33,17 @@ AccountMgr::~AccountMgr() ClearRBAC(); } -AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email = "") +AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email /*= ""*/) { if (utf8length(username) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; // username's too long + return AccountOpResult::AOR_NAME_TOO_LONG; // username's too long - normalizeString(username); - normalizeString(password); - normalizeString(email); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + Utf8ToUpperOnlyLatin(email); if (GetId(username)) - return AOR_NAME_ALREADY_EXIST; // username does already exist + return AccountOpResult::AOR_NAME_ALREADY_EXIST; // username does already exist PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); @@ -57,7 +57,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT); LoginDatabase.Execute(stmt); - return AOR_OK; // everything's fine + return AccountOpResult::AOR_OK; // everything's fine } AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) @@ -68,7 +68,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) - return AOR_NAME_NOT_EXIST; + return AccountOpResult::AOR_NAME_NOT_EXIST; // Obtain accounts characters stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); @@ -129,7 +129,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) LoginDatabase.CommitTransaction(trans); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) @@ -140,16 +140,16 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) - return AOR_NAME_NOT_EXIST; + return AccountOpResult::AOR_NAME_NOT_EXIST; if (utf8length(newUsername) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; + return AccountOpResult::AOR_NAME_TOO_LONG; if (utf8length(newPassword) > MAX_ACCOUNT_STR) - return AOR_PASS_TOO_LONG; + return AccountOpResult::AOR_PASS_TOO_LONG; - normalizeString(newUsername); - normalizeString(newPassword); + Utf8ToUpperOnlyLatin(newUsername); + Utf8ToUpperOnlyLatin(newPassword); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME); @@ -159,7 +159,7 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) @@ -169,17 +169,17 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass if (!GetName(accountId, username)) { sScriptMgr->OnFailedPasswordChange(accountId); - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist } if (utf8length(newPassword) > MAX_ACCOUNT_STR) { sScriptMgr->OnFailedPasswordChange(accountId); - return AOR_PASS_TOO_LONG; + return AccountOpResult::AOR_PASS_TOO_LONG; } - normalizeString(username); - normalizeString(newPassword); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newPassword); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD); @@ -197,7 +197,7 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass LoginDatabase.Execute(stmt); sScriptMgr->OnPasswordChange(accountId); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) @@ -207,17 +207,17 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) if (!GetName(accountId, username)) { sScriptMgr->OnFailedEmailChange(accountId); - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist } if (utf8length(newEmail) > MAX_EMAIL_STR) { sScriptMgr->OnFailedEmailChange(accountId); - return AOR_EMAIL_TOO_LONG; + return AccountOpResult::AOR_EMAIL_TOO_LONG; } - normalizeString(username); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newEmail); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL); @@ -227,7 +227,7 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) LoginDatabase.Execute(stmt); sScriptMgr->OnEmailChange(accountId); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmail) @@ -235,19 +235,16 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai std::string username; if (!GetName(accountId, username)) - { - sScriptMgr->OnFailedEmailChange(accountId); - return AOR_NAME_NOT_EXIST; // account doesn't exist - } + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist if (utf8length(newEmail) > MAX_EMAIL_STR) { sScriptMgr->OnFailedEmailChange(accountId); - return AOR_EMAIL_TOO_LONG; + return AccountOpResult::AOR_EMAIL_TOO_LONG; } - normalizeString(username); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newEmail); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REG_EMAIL); @@ -257,7 +254,7 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai LoginDatabase.Execute(stmt); sScriptMgr->OnEmailChange(accountId); - return AOR_OK; + return AccountOpResult::AOR_OK; } uint32 AccountMgr::GetId(std::string const& username) @@ -325,8 +322,8 @@ bool AccountMgr::CheckPassword(uint32 accountId, std::string password) if (!GetName(accountId, username)) return false; - normalizeString(username); - normalizeString(password); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); stmt->setUInt32(0, accountId); @@ -344,8 +341,8 @@ bool AccountMgr::CheckEmail(uint32 accountId, std::string newEmail) if (!GetEmail(accountId, oldEmail)) return false; - normalizeString(oldEmail); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(oldEmail); + Utf8ToUpperOnlyLatin(newEmail); if (strcmp(oldEmail.c_str(), newEmail.c_str()) == 0) return true; @@ -363,19 +360,6 @@ uint32 AccountMgr::GetCharactersCount(uint32 accountId) return (result) ? (*result)[0].GetUInt64() : 0; } -bool AccountMgr::normalizeString(std::string& utf8String) -{ - wchar_t buffer[MAX_ACCOUNT_STR+1]; - - size_t maxLength = MAX_ACCOUNT_STR; - if (!Utf8toWStr(utf8String, buffer, maxLength)) - return false; - - std::transform(&buffer[0], buffer+maxLength, &buffer[0], wcharToUpperOnlyLatin); - - return WStrToUtf8(buffer, maxLength, utf8String); -} - std::string AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) { SHA1Hash sha; diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index c4b4bd93728..add00ec7feb 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -21,7 +21,7 @@ #include "RBAC.h" -enum AccountOpResult +enum class AccountOpResult : uint8 { AOR_OK, AOR_NAME_TOO_LONG, @@ -39,6 +39,7 @@ enum PasswordChangeSecurity PW_RBAC }; +#define MAX_PASS_STR 16 #define MAX_ACCOUNT_STR 16 #define MAX_EMAIL_STR 64 @@ -61,7 +62,7 @@ class AccountMgr return &instance; } - AccountOpResult CreateAccount(std::string username, std::string password, std::string email); + AccountOpResult CreateAccount(std::string username, std::string password, std::string email = ""); static AccountOpResult DeleteAccount(uint32 accountId); static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); @@ -78,7 +79,6 @@ class AccountMgr static uint32 GetCharactersCount(uint32 accountId); static std::string CalculateShaPassHash(std::string const& name, std::string const& password); - static bool normalizeString(std::string& utf8String); static bool IsPlayerAccount(uint32 gmlevel); static bool IsAdminAccount(uint32 gmlevel); static bool IsConsoleAccount(uint32 gmlevel); diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp new file mode 100644 index 00000000000..23c1b7cdd61 --- /dev/null +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "AccountMgr.h" +#include "BattlenetAccountMgr.h" +#include "DatabaseEnv.h" +#include "Util.h" +#include "SHA256.h" + +AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, std::string password) +{ + if (utf8length(email) > MAX_BNET_EMAIL_STR) + return AccountOpResult::AOR_NAME_TOO_LONG; + + if (utf8length(password) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; + + Utf8ToUpperOnlyLatin(email); + Utf8ToUpperOnlyLatin(password); + + if (GetId(email)) + return AccountOpResult::AOR_NAME_ALREADY_EXIST; + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT); + stmt->setString(0, email); + stmt->setString(1, CalculateShaPassHash(email, password)); + LoginDatabase.Execute(stmt); + + return AccountOpResult::AOR_OK; +} + +AccountOpResult Battlenet::AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) +{ + std::string username; + if (!GetName(accountId, username)) + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newPassword); + if (utf8length(newPassword) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD); + stmt->setString(0, CalculateShaPassHash(username, newPassword)); + stmt->setUInt32(1, accountId); + LoginDatabase.Execute(stmt); + + return AccountOpResult::AOR_OK; +} + +uint32 Battlenet::AccountMgr::GetId(std::string const& username) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL); + stmt->setString(0, username); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + return (*result)[0].GetUInt32(); + + return 0; +} + +uint32 Battlenet::AccountMgr::GetIdByGameAccount(uint32 gameAccountId) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT); + stmt->setUInt32(0, gameAccountId); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + return (*result)[0].GetUInt32(); + + return 0; +} + +bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); + stmt->setUInt32(0, accountId); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + { + name = (*result)[0].GetString(); + return true; + } + + return false; +} + +bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password) +{ + std::string username; + + if (!GetName(accountId, username)) + return false; + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); + stmt->setUInt32(0, accountId); + stmt->setString(1, CalculateShaPassHash(username, password)); + + return LoginDatabase.Query(stmt) != nullptr; +} + +std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) +{ + SHA256Hash email; + email.UpdateData(name); + email.Finalize(); + + SHA256Hash sha; + sha.UpdateData(ByteArrayToHexStr(email.GetDigest(), email.GetLength())); + sha.UpdateData(":"); + sha.UpdateData(password); + sha.Finalize(); + + return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength(), true); +} + +bool Battlenet::AccountMgr::GetAccountIdAndIndex(std::string const& account, uint32* battlenetAccountId, uint8* battlenetAccountIndex) +{ + Tokenizer tokens(account, '#'); + if (tokens.size() != 2) + return false; + + if (!battlenetAccountId) + return false; + + *battlenetAccountId = atol(tokens[0]); + if (!*battlenetAccountId) + return false; + + if (battlenetAccountIndex) + { + *battlenetAccountIndex = atol(tokens[1]); + if (!*battlenetAccountIndex) + return false; + } + + return true; +} diff --git a/src/server/game/Accounts/BattlenetAccountMgr.h b/src/server/game/Accounts/BattlenetAccountMgr.h new file mode 100644 index 00000000000..c41a54189e5 --- /dev/null +++ b/src/server/game/Accounts/BattlenetAccountMgr.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BattlenetAccountMgr_h__ +#define BattlenetAccountMgr_h__ + +#include "Define.h" +#include <string> + +enum class AccountOpResult : uint8; + +#define MAX_BNET_EMAIL_STR 320 + +namespace Battlenet +{ + namespace AccountMgr + { + AccountOpResult CreateBattlenetAccount(std::string email, std::string password); + AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); + bool CheckPassword(uint32 accountId, std::string password); + + uint32 GetId(std::string const& username); + bool GetName(uint32 accountId, std::string& name); + uint32 GetIdByGameAccount(uint32 gameAccountId); + + std::string CalculateShaPassHash(std::string const& name, std::string const& password); + bool GetAccountIdAndIndex(std::string const& account, uint32* battlenetAccountId, uint8* battlenetAccountIndex); + } +} + +#endif // BattlenetAccountMgr_h__ diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index f2637a5febc..d7cde6d1794 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -110,13 +110,13 @@ enum RBACPermissions RBAC_PERM_COMMAND_RBAC_ACC_PERM_DENY = 204, RBAC_PERM_COMMAND_RBAC_ACC_PERM_REVOKE = 205, RBAC_PERM_COMMAND_RBAC_LIST = 206, - // 207 - reuse - // 208 - reuse - // 209 - reuse - // 210 - reuse - // 211 - reuse - // 212 - reuse - // 213 - reuse + RBAC_PERM_COMMAND_BNET_ACCOUNT = 207, + RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE = 208, + RBAC_PERM_COMMAND_BNET_ACCOUNT_LOCK_COUNTRY = 209, + RBAC_PERM_COMMAND_BNET_ACCOUNT_LOCK_IP = 210, + RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD = 211, + RBAC_PERM_COMMAND_BNET_ACCOUNT_SET = 212, + RBAC_PERM_COMMAND_BNET_ACCOUNT_SET_PASSWORD = 213, // 214 - reuse // 215 - reuse // 216 - reuse diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index d54b0572252..17db09eedfb 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -28,6 +28,7 @@ #include "DisableMgr.h" #include "GameEventMgr.h" #include "GridNotifiersImpl.h" +#include "Group.h" #include "Guild.h" #include "GuildMgr.h" #include "InstanceScript.h" @@ -73,7 +74,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) return false; } - switch (criteria->requiredType) + switch (criteria->type) { case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: @@ -103,7 +104,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) default: if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->requiredType); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->type); return false; } break; @@ -113,27 +114,32 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) { case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: case ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT: - case ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY: return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE: if (!creature.id || !sObjectMgr->GetCreatureTemplate(creature.id)) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing creature id in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, creature.id); + criteria->ID, criteria->type, dataType, creature.id); return false; } return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE: + if (!classRace.class_id && !classRace.race_id) + { + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", + criteria->ID, criteria->type, dataType); + return false; + } if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, classRace.class_id); + criteria->ID, criteria->type, dataType, classRace.class_id); return false; } if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, classRace.race_id); + criteria->ID, criteria->type, dataType, classRace.race_id); return false; } return true; @@ -141,15 +147,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (health.percent < 1 || health.percent > 100) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) has wrong percent value in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, health.percent); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD: - if (player_dead.own_team_flag > 1) - { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD (%u) has wrong boolean value1 (%u).", - criteria->ID, criteria->requiredType, dataType, player_dead.own_team_flag); + criteria->ID, criteria->type, dataType, health.percent); return false; } return true; @@ -160,36 +158,28 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!spellEntry) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell id in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id); + criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id); return false; } if (aura.effect_idx >= 3) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell effect index in value2 (%u), ignored.", - criteria->ID, criteria->requiredType, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx); + criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx); return false; } if (!spellEntry->Effects[aura.effect_idx].ApplyAuraName) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has non-aura spell effect (ID: %u Effect: %u), ignores.", - criteria->ID, criteria->requiredType, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx); + criteria->ID, criteria->type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx); return false; } return true; } - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA: - if (!GetAreaEntryByAreaID(area.id)) - { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) has wrong area id in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, area.id); - return false; - } - return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE: if (value.compType >= COMP_TYPE_MAX) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE (%u) has wrong ComparisionType in value2 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, value.compType); + criteria->ID, criteria->type, dataType, value.compType); return false; } return true; @@ -197,7 +187,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (level.minlevel > STRONG_MAX_LEVEL) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL (%u) has wrong minlevel in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, level.minlevel); + criteria->ID, criteria->type, dataType, level.minlevel); return false; } return true; @@ -205,7 +195,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (gender.gender > GENDER_NONE) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER (%u) has wrong gender in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, gender.gender); + criteria->ID, criteria->type, dataType, gender.gender); return false; } return true; @@ -213,15 +203,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!ScriptId) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT (%u) does not have ScriptName set, ignored.", - criteria->ID, criteria->requiredType, dataType); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: - if (difficulty.difficulty >= MAX_DIFFICULTY) - { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY (%u) has wrong difficulty in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, difficulty.difficulty); + criteria->ID, criteria->type, dataType); return false; } return true; @@ -229,7 +211,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (map_players.maxcount <= 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT (%u) has wrong max players count in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, map_players.maxcount); + criteria->ID, criteria->type, dataType, map_players.maxcount); return false; } return true; @@ -237,7 +219,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (team.team != ALLIANCE && team.team != HORDE) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM (%u) has unknown team in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, team.team); + criteria->ID, criteria->type, dataType, team.team); return false; } return true; @@ -245,7 +227,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (drunk.state >= MAX_DRUNKEN) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK (%u) has unknown drunken state in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, drunk.state); + criteria->ID, criteria->type, dataType, drunk.state); return false; } return true; @@ -253,25 +235,28 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!sHolidaysStore.LookupEntry(holiday.id)) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY (%u) has unknown holiday in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, holiday.id); + criteria->ID, criteria->type, dataType, holiday.id); return false; } return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT: + { + GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); + if (game_event.id < 1 || game_event.id >= events.size()) + { + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT (%u) has unknown game_event in value1 (%u), ignored.", + criteria->ID, criteria->type, dataType, game_event.id); + return false; + } + return true; + } case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: return true; // not check correctness node indexes case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: if (equipped_item.item_quality >= MAX_ITEM_QUALITY) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM (%u) has unknown quality state in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, equipped_item.item_quality); - return false; - } - return true; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID: - if (!sMapStore.LookupEntry(map_id.mapId)) - { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID (%u) has unknown map id in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, map_id.mapId); + criteria->ID, criteria->type, dataType, equipped_item.item_quality); return false; } return true; @@ -279,19 +264,19 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!classRace.class_id && !classRace.race_id) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", - criteria->ID, criteria->requiredType, dataType); + criteria->ID, criteria->type, dataType); return false; } if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, classRace.class_id); + criteria->ID, criteria->type, dataType, classRace.class_id); return false; } if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", - criteria->ID, criteria->requiredType, dataType, classRace.race_id); + criteria->ID, criteria->type, dataType, classRace.race_id); return false; } return true; @@ -299,17 +284,17 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!sCharTitlesStore.LookupEntry(known_title.title_id)) { TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE (%u) have unknown title_id in value1 (%u), ignore.", - criteria->ID, criteria->requiredType, dataType, known_title.title_id); + criteria->ID, criteria->type, dataType, known_title.title_id); return false; } return true; default: - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->requiredType, dataType); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->type, dataType); return false; } } -bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscvalue1 /*= 0*/) const +bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscValue1 /*= 0*/) const { switch (dataType) { @@ -339,25 +324,12 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un if (!target || target->GetTypeId() != TYPEID_PLAYER) return false; return !target->HealthAbovePct(health.percent); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD: - if (target && !target->IsAlive()) - if (const Player* player = target->ToPlayer()) - if (player->GetDeathTimer() != 0) - // flag set == must be same team, not set == different team - return (player->GetTeam() == source->GetTeam()) == (player_dead.own_team_flag != 0); - return false; case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA: return source->HasAuraEffect(aura.spell_id, aura.effect_idx); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA: - { - uint32 zone_id, area_id; - source->GetZoneAndAreaId(zone_id, area_id); - return area.id == zone_id || area.id == area_id; - } case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA: return target && target->HasAuraEffect(aura.spell_id, aura.effect_idx); case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE: - return CompareValues(ComparisionType(value.compType), miscvalue1, value.value); + return CompareValues(ComparisionType(value.compType), miscValue1, value.value); case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL: if (!target) return false; @@ -368,11 +340,6 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un return target->getGender() == gender.gender; case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT: return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(target)); - case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: - if (source->GetMap()->IsRaid()) - if (source->GetMap()->Is25ManRaid() != ((difficulty.difficulty & RAID_DIFFICULTY_MASK_25MAN) != 0)) - return false; - return source->GetMap()->GetSpawnMode() >= difficulty.difficulty; case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM: @@ -383,6 +350,8 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un return Player::GetDrunkenstateByValue(source->GetDrunkValue()) >= DrunkenState(drunk.state); case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY: return IsHolidayActive(HolidayIds(holiday.id)); + case ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT: + return IsEventActive(game_event.id); case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: { Battleground* bg = source->GetBattleground(); @@ -410,34 +379,22 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un dataType, criteria_id, map->GetId()); return false; } - return instance->CheckAchievementCriteriaMeet(criteria_id, source, target, miscvalue1); + return instance->CheckAchievementCriteriaMeet(criteria_id, source, target, miscValue1); } case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: { - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscvalue1); + ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1); if (!pProto) return false; return pProto->ItemLevel >= equipped_item.item_level && pProto->Quality >= equipped_item.item_quality; } case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID: return source->GetMapId() == map_id.mapId; - case ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY: - { - time_t birthday_start = time_t(sWorld->getIntConfig(CONFIG_BIRTHDAY_TIME)); - tm birthday_tm; - localtime_r(&birthday_start, &birthday_tm); - - // exactly N birthday - birthday_tm.tm_year += birthday_login.nth_birthday; - - time_t birthday = mktime(&birthday_tm); - time_t now = sWorld->GetGameTime(); - return now <= birthday + DAY && now >= birthday; - } case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE: { if (CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(known_title.title_id)) - return source->HasTitle(titleInfo->bit_index); + return source && source->HasTitle(titleInfo->bit_index); + return false; } default: @@ -446,52 +403,97 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un return false; } -bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target, uint32 miscvalue /*= 0*/) const +bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target, uint32 miscValue /*= 0*/) const { for (Storage::const_iterator itr = storage.begin(); itr != storage.end(); ++itr) - if (!itr->Meets(criteria_id, source, target, miscvalue)) + if (!itr->Meets(criteria_id, source, target, miscValue)) return false; return true; } -AchievementMgr::AchievementMgr(Player* player) +template<class T> +AchievementMgr<T>::AchievementMgr(T* owner): _owner(owner), _achievementPoints(0) { } + +template<class T> +AchievementMgr<T>::~AchievementMgr() { } + +template<class T> +void AchievementMgr<T>::SendPacket(WorldPacket* data) const { } + +template<> +void AchievementMgr<Guild>::SendPacket(WorldPacket* data) const { - m_player = player; + GetOwner()->BroadcastPacket(data); } -AchievementMgr::~AchievementMgr() { } +template<> +void AchievementMgr<Player>::SendPacket(WorldPacket* data) const +{ + GetOwner()->GetSession()->SendPacket(data); +} -void AchievementMgr::Reset() +template<class T> +void AchievementMgr<T>::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry) { - for (CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter != m_completedAchievements.end(); ++iter) - { - WorldPacket data(SMSG_ACHIEVEMENT_DELETED, 4); - data << uint32(iter->first); - m_player->SendDirectMessage(&data); - } + if (!entry) + return; - for (CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter != m_criteriaProgress.end(); ++iter) - { - WorldPacket data(SMSG_CRITERIA_DELETED, 4); - data << uint32(iter->first); - m_player->SendDirectMessage(&data); - } + CriteriaProgressMap::iterator criteriaProgress = m_criteriaProgress.find(entry->ID); + if (criteriaProgress == m_criteriaProgress.end()) + return; - m_completedAchievements.clear(); - m_criteriaProgress.clear(); - DeleteFromDB(m_player->GetGUIDLow()); + WorldPacket data(SMSG_CRITERIA_DELETED, 4); + data << uint32(entry->ID); + SendPacket(&data); - // re-fill data - CheckAllAchievementCriteria(); + m_criteriaProgress.erase(criteriaProgress); } -void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1, uint32 miscvalue2, bool evenIfCriteriaComplete) +template<> +void AchievementMgr<Guild>::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry) { - TC_LOG_DEBUG("achievement", "AchievementMgr::ResetAchievementCriteria(%u, %u, %u)", type, miscvalue1, miscvalue2); + if (!entry) + return; + + CriteriaProgressMap::iterator criteriaProgress = m_criteriaProgress.find(entry->ID); + if (criteriaProgress == m_criteriaProgress.end()) + return; + + ObjectGuid guid = GetOwner()->GetGUID(); + + WorldPacket data(SMSG_GUILD_CRITERIA_DELETED, 4 + 8); + data.WriteBit(guid[6]); + data.WriteBit(guid[5]); + data.WriteBit(guid[7]); + data.WriteBit(guid[0]); + data.WriteBit(guid[1]); + data.WriteBit(guid[3]); + data.WriteBit(guid[2]); + data.WriteBit(guid[4]); + + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[7]); + data << uint32(entry->ID); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[6]); + + SendPacket(&data); + + m_criteriaProgress.erase(criteriaProgress); +} + +template<class T> +void AchievementMgr<T>::ResetAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, bool evenIfCriteriaComplete) +{ + TC_LOG_DEBUG("achievement", "ResetAchievementCriteria(%u, " UI64FMTD ", " UI64FMTD ")", type, miscValue1, miscValue2); // disable for gamemasters with GM-mode enabled - if (m_player->IsGameMaster()) + if (GetOwner()->IsGameMaster()) return; AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type); @@ -499,7 +501,7 @@ void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaTypes type, uin { AchievementCriteriaEntry const* achievementCriteria = (*i); - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->referredAchievement); + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->achievement); if (!achievement) continue; @@ -508,9 +510,9 @@ void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaTypes type, uin continue; for (uint8 j = 0; j < MAX_CRITERIA_REQUIREMENTS; ++j) - if (achievementCriteria->additionalRequirements[j].additionalRequirement_type == miscvalue1 && + if (achievementCriteria->additionalRequirements[j].additionalRequirement_type == miscValue1 && (!achievementCriteria->additionalRequirements[j].additionalRequirement_value || - achievementCriteria->additionalRequirements[j].additionalRequirement_value == miscvalue2)) + achievementCriteria->additionalRequirements[j].additionalRequirement_value == miscValue2)) { RemoveCriteriaProgress(achievementCriteria); break; @@ -518,7 +520,19 @@ void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaTypes type, uin } } -void AchievementMgr::DeleteFromDB(uint32 lowguid) +template<> +void AchievementMgr<Guild>::ResetAchievementCriteria(AchievementCriteriaTypes /*type*/, uint64 /*miscValue1*/, uint64 /*miscValue2*/, bool /*evenIfCriteriaComplete*/) +{ + // Not needed +} + +template<class T> +void AchievementMgr<T>::DeleteFromDB(uint32 /*lowguid*/) +{ +} + +template<> +void AchievementMgr<Player>::DeleteFromDB(uint32 lowguid) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); @@ -533,7 +547,29 @@ void AchievementMgr::DeleteFromDB(uint32 lowguid) CharacterDatabase.CommitTransaction(trans); } -void AchievementMgr::SaveToDB(SQLTransaction& trans) +template<> +void AchievementMgr<Guild>::DeleteFromDB(uint32 lowguid) +{ + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GUILD_ACHIEVEMENTS); + stmt->setUInt32(0, lowguid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GUILD_ACHIEVEMENT_CRITERIA); + stmt->setUInt32(0, lowguid); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); +} + +template<class T> +void AchievementMgr<T>::SaveToDB(SQLTransaction& /*trans*/) +{ +} + +template<> +void AchievementMgr<Player>::SaveToDB(SQLTransaction& trans) { if (!m_completedAchievements.empty()) { @@ -544,11 +580,11 @@ void AchievementMgr::SaveToDB(SQLTransaction& trans) PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT); stmt->setUInt16(0, iter->first); - stmt->setUInt32(1, GetPlayer()->GetGUID()); + stmt->setUInt32(1, GetOwner()->GetGUID()); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT); - stmt->setUInt32(0, GetPlayer()->GetGUID()); + stmt->setUInt32(0, GetOwner()->GetGUID()); stmt->setUInt16(1, iter->first); stmt->setUInt32(2, uint32(iter->second.date)); trans->Append(stmt); @@ -565,14 +601,14 @@ void AchievementMgr::SaveToDB(SQLTransaction& trans) continue; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA); - stmt->setUInt32(0, GetPlayer()->GetGUID()); + stmt->setUInt32(0, GetOwner()->GetGUID()); stmt->setUInt16(1, iter->first); trans->Append(stmt); if (iter->second.counter) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS); - stmt->setUInt32(0, GetPlayer()->GetGUID()); + stmt->setUInt32(0, GetOwner()->GetGUID()); stmt->setUInt16(1, iter->first); stmt->setUInt32(2, iter->second.counter); stmt->setUInt32(3, uint32(iter->second.date)); @@ -584,7 +620,61 @@ void AchievementMgr::SaveToDB(SQLTransaction& trans) } } -void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) +template<> +void AchievementMgr<Guild>::SaveToDB(SQLTransaction& trans) +{ + PreparedStatement* stmt; + std::ostringstream guidstr; + for (CompletedAchievementMap::const_iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) + { + if (!itr->second.changed) + continue; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_ACHIEVEMENT); + stmt->setUInt32(0, GetOwner()->GetId()); + stmt->setUInt16(1, itr->first); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_ACHIEVEMENT); + stmt->setUInt32(0, GetOwner()->GetId()); + stmt->setUInt16(1, itr->first); + stmt->setUInt32(2, itr->second.date); + for (std::set<uint64>::const_iterator gItr = itr->second.guids.begin(); gItr != itr->second.guids.end(); ++gItr) + guidstr << GUID_LOPART(*gItr) << ','; + + stmt->setString(3, guidstr.str()); + trans->Append(stmt); + + guidstr.str(""); + } + + for (CriteriaProgressMap::const_iterator itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) + { + if (!itr->second.changed) + continue; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_ACHIEVEMENT_CRITERIA); + stmt->setUInt32(0, GetOwner()->GetId()); + stmt->setUInt16(1, itr->first); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_ACHIEVEMENT_CRITERIA); + stmt->setUInt32(0, GetOwner()->GetId()); + stmt->setUInt16(1, itr->first); + stmt->setUInt64(2, itr->second.counter); + stmt->setUInt32(3, itr->second.date); + stmt->setUInt32(4, GUID_LOPART(itr->second.CompletedGUID)); + trans->Append(stmt); + } +} + +template<class T> +void AchievementMgr<T>::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) +{ +} + +template<> +void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) { if (achievementResult) { @@ -602,22 +692,26 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQ ca.date = time_t(fields[1].GetUInt32()); ca.changed = false; + _achievementPoints += achievement->points; + // title achievement rewards are retroactive if (AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement)) - if (uint32 titleId = reward->titleId[Player::TeamForRace(GetPlayer()->getRace()) == ALLIANCE ? 0 : 1]) + if (uint32 titleId = reward->titleId[Player::TeamForRace(GetOwner()->getRace()) == ALLIANCE ? 0 : 1]) if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId)) - GetPlayer()->SetTitle(titleEntry); + GetOwner()->SetTitle(titleEntry); - } while (achievementResult->NextRow()); + } + while (achievementResult->NextRow()); } if (criteriaResult) { + time_t now = time(NULL); do { Field* fields = criteriaResult->Fetch(); uint32 id = fields[0].GetUInt16(); - uint32 counter = fields[1].GetUInt32(); + uint64 counter = fields[1].GetUInt64(); time_t date = time_t(fields[2].GetUInt32()); AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(id); @@ -627,81 +721,242 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQ TC_LOG_ERROR("achievement", "Non-existing achievement criteria %u data removed from table `character_achievement_progress`.", id); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA); - stmt->setUInt16(0, uint16(id)); - CharacterDatabase.Execute(stmt); continue; } - if (criteria->timeLimit && time_t(date + criteria->timeLimit) < time(NULL)) + if (criteria->timeLimit && time_t(date + criteria->timeLimit) < now) + continue; + + CriteriaProgress& progress = m_criteriaProgress[id]; + progress.counter = counter; + progress.date = date; + progress.changed = false; + } + while (criteriaResult->NextRow()); + } +} + +template<> +void AchievementMgr<Guild>::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult) +{ + if (achievementResult) + { + do + { + Field* fields = achievementResult->Fetch(); + uint32 achievementid = fields[0].GetUInt16(); + + // must not happen: cleanup at server startup in sAchievementMgr->LoadCompletedAchievements() + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementid); + if (!achievement) + continue; + + CompletedAchievementData& ca = m_completedAchievements[achievementid]; + ca.date = time_t(fields[1].GetUInt32()); + Tokenizer guids(fields[2].GetString(), ' '); + for (uint32 i = 0; i < guids.size(); ++i) + ca.guids.insert(MAKE_NEW_GUID(atol(guids[i]), 0, HIGHGUID_PLAYER)); + + ca.changed = false; + + _achievementPoints += achievement->points; + } + while (achievementResult->NextRow()); + } + + if (criteriaResult) + { + time_t now = time(NULL); + do + { + Field* fields = criteriaResult->Fetch(); + uint32 id = fields[0].GetUInt16(); + uint32 counter = fields[1].GetUInt32(); + time_t date = time_t(fields[2].GetUInt32()); + uint64 guid = fields[3].GetUInt32(); + + AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(id); + if (!criteria) + { + // we will remove not existed criteria for all guilds + TC_LOG_ERROR("achievement", "Non-existing achievement criteria %u data removed from table `guild_achievement_progress`.", id); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA_GUILD); + stmt->setUInt16(0, uint16(id)); + CharacterDatabase.Execute(stmt); + continue; + } + + if (criteria->timeLimit && time_t(date + criteria->timeLimit) < now) continue; CriteriaProgress& progress = m_criteriaProgress[id]; progress.counter = counter; progress.date = date; + progress.CompletedGUID = MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER); progress.changed = false; } while (criteriaResult->NextRow()); } } -void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) const +template<class T> +void AchievementMgr<T>::Reset() { - if (GetPlayer()->GetSession()->PlayerLoading()) - return; +} - // Don't send for achievements with ACHIEVEMENT_FLAG_TRACKING +template<> +void AchievementMgr<Player>::Reset() +{ + for (CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter != m_completedAchievements.end(); ++iter) + { + WorldPacket data(SMSG_ACHIEVEMENT_DELETED, 4); + data << uint32(iter->first); + SendPacket(&data); + } + + for (CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter != m_criteriaProgress.end(); ++iter) + { + WorldPacket data(SMSG_CRITERIA_DELETED, 4); + data << uint32(iter->first); + SendPacket(&data); + } + + m_completedAchievements.clear(); + _achievementPoints = 0; + m_criteriaProgress.clear(); + DeleteFromDB(GetOwner()->GetGUIDLow()); + + // re-fill data + CheckAllAchievementCriteria(GetOwner()); +} + +template<> +void AchievementMgr<Guild>::Reset() +{ + ObjectGuid guid = GetOwner()->GetGUID(); + for (CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter != m_completedAchievements.end(); ++iter) + { + WorldPacket data(SMSG_GUILD_ACHIEVEMENT_DELETED, 4); + data.WriteBit(guid[4]); + data.WriteBit(guid[1]); + data.WriteBit(guid[2]); + data.WriteBit(guid[3]); + data.WriteBit(guid[0]); + data.WriteBit(guid[7]); + data.WriteBit(guid[5]); + data.WriteBit(guid[6]); + data << uint32(iter->first); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[7]); + data.AppendPackedTime(iter->second.date); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[2]); + SendPacket(&data); + } + + while (!m_criteriaProgress.empty()) + if (AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(m_criteriaProgress.begin()->first)) + RemoveCriteriaProgress(criteria); + + _achievementPoints = 0; + m_completedAchievements.clear(); + DeleteFromDB(GetOwner()->GetId()); +} + +template<class T> +void AchievementMgr<T>::SendAchievementEarned(AchievementEntry const* achievement) const +{ + // Don't send for achievements with ACHIEVEMENT_FLAG_HIDDEN if (achievement->flags & ACHIEVEMENT_FLAG_HIDDEN) return; - #ifdef TRINITY_DEBUG - TC_LOG_DEBUG("achievement", "AchievementMgr::SendAchievementEarned(%u)", achievement->ID); - #endif + TC_LOG_DEBUG("achievement", "AchievementMgr::SendAchievementEarned(%u)", achievement->ID); - if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildId())) + if (Guild* guild = sGuildMgr->GetGuildById(GetOwner()->GetGuildId())) { - Trinity::AchievementChatBuilder _builder(GetPlayer(), CHAT_MSG_GUILD_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, achievement->ID); + Trinity::AchievementChatBuilder _builder(GetOwner(), CHAT_MSG_GUILD_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, achievement->ID); Trinity::LocalizedPacketDo<Trinity::AchievementChatBuilder> _localizer(_builder); - guild->BroadcastWorker(_localizer, GetPlayer()); + guild->BroadcastWorker(_localizer, GetOwner()); } if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_KILL | ACHIEVEMENT_FLAG_REALM_FIRST_REACH)) { // broadcast realm first reached - WorldPacket data(SMSG_SERVER_FIRST_ACHIEVEMENT, GetPlayer()->GetName().size() + 1 + 8 + 4 + 4); - data << GetPlayer()->GetName(); - data << uint64(GetPlayer()->GetGUID()); + WorldPacket data(SMSG_SERVER_FIRST_ACHIEVEMENT, GetOwner()->GetName().size() + 1 + 8 + 4 + 4); + data << GetOwner()->GetName(); + data << uint64(GetOwner()->GetGUID()); data << uint32(achievement->ID); data << uint32(0); // 1=link supplied string as player name, 0=display plain string sWorld->SendGlobalMessage(&data); } // if player is in world he can tell his friends about new achievement - else if (GetPlayer()->IsInWorld()) + else if (GetOwner()->IsInWorld()) { - Trinity::AchievementChatBuilder _builder(GetPlayer(), CHAT_MSG_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, achievement->ID); + Trinity::AchievementChatBuilder _builder(GetOwner(), CHAT_MSG_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, achievement->ID); Trinity::LocalizedPacketDo<Trinity::AchievementChatBuilder> _localizer(_builder); - Trinity::PlayerDistWorker<Trinity::LocalizedPacketDo<Trinity::AchievementChatBuilder> > _worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _localizer); - GetPlayer()->VisitNearbyWorldObject(sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _worker); + Trinity::PlayerDistWorker<Trinity::LocalizedPacketDo<Trinity::AchievementChatBuilder> > _worker(GetOwner(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _localizer); + GetOwner()->VisitNearbyWorldObject(sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _worker); } WorldPacket data(SMSG_ACHIEVEMENT_EARNED, 8+4+8); - data.append(GetPlayer()->GetPackGUID()); + data.append(GetOwner()->GetPackGUID()); data << uint32(achievement->ID); data.AppendPackedTime(time(NULL)); - data << uint32(0); - GetPlayer()->SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); + data << uint32(0); // does not notify player ingame + GetOwner()->SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); +} + +template<> +void AchievementMgr<Guild>::SendAchievementEarned(AchievementEntry const* achievement) const +{ + ObjectGuid guid = GetOwner()->GetGUID(); + + WorldPacket data(SMSG_GUILD_ACHIEVEMENT_EARNED, 8+4+8); + data.WriteBit(guid[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[0]); + data.WriteBit(guid[7]); + data.WriteBit(guid[4]); + data.WriteBit(guid[6]); + data.WriteBit(guid[2]); + data.WriteBit(guid[5]); + + data.WriteByteSeq(guid[2]); + data.AppendPackedTime(time(NULL)); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[3]); + data << uint32(achievement->ID); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[6]); + + SendPacket(&data); +} + +template<class T> +void AchievementMgr<T>::SendCriteriaUpdate(AchievementCriteriaEntry const* /*entry*/, CriteriaProgress const* /*progress*/, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const +{ } -void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const +template<> +void AchievementMgr<Player>::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const { - WorldPacket data(SMSG_CRITERIA_UPDATE, 8+4+8); + WorldPacket data(SMSG_CRITERIA_UPDATE, 8 + 4 + 8); data << uint32(entry->ID); // the counter is packed like a packed Guid data.appendPackGUID(progress->counter); - data.append(GetPlayer()->GetPackGUID()); + data.appendPackGUID(GetOwner()->GetGUID()); if (!entry->timeLimit) data << uint32(0); else @@ -709,20 +964,75 @@ void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, C data.AppendPackedTime(progress->date); data << uint32(timeElapsed); // time elapsed in seconds data << uint32(0); // unk - GetPlayer()->SendDirectMessage(&data); + SendPacket(&data); +} + +template<> +void AchievementMgr<Guild>::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 /*timeElapsed*/, bool /*timedCompleted*/) const +{ + //will send response to criteria progress request + WorldPacket data(SMSG_GUILD_CRITERIA_DATA, 3 + 1 + 1 + 8 + 8 + 4 + 4 + 4 + 4 + 4); + + ObjectGuid counter = progress->counter; // for accessing every byte individually + ObjectGuid guid = progress->CompletedGUID; + + data.WriteBits(1, 21); + data.WriteBit(counter[4]); + data.WriteBit(counter[1]); + data.WriteBit(guid[2]); + data.WriteBit(counter[3]); + data.WriteBit(guid[1]); + data.WriteBit(counter[5]); + data.WriteBit(counter[0]); + data.WriteBit(guid[3]); + data.WriteBit(counter[2]); + data.WriteBit(guid[7]); + data.WriteBit(guid[5]); + data.WriteBit(guid[0]); + data.WriteBit(counter[6]); + data.WriteBit(guid[6]); + data.WriteBit(counter[7]); + data.WriteBit(guid[4]); + + data.FlushBits(); + + data.WriteByteSeq(guid[5]); + data << uint32(progress->date); // unknown date + data.WriteByteSeq(counter[3]); + data.WriteByteSeq(counter[7]); + data << uint32(progress->date); // unknown date + data.WriteByteSeq(counter[6]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(counter[4]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(counter[0]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(counter[1]); + data.WriteByteSeq(guid[6]); + data << uint32(progress->date); // last update time (not packed!) + data << uint32(entry->ID); + data.WriteByteSeq(counter[5]); + data << uint32(0); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(counter[2]); + data.WriteByteSeq(guid[0]); + + SendPacket(&data); } /** * called at player login. The player might have fulfilled some achievements when the achievement system wasn't working yet */ -void AchievementMgr::CheckAllAchievementCriteria() +template<class T> +void AchievementMgr<T>::CheckAllAchievementCriteria(Player* referencePlayer) { // suppress sending packets for (uint32 i=0; i<ACHIEVEMENT_CRITERIA_TYPE_TOTAL; ++i) - UpdateAchievementCriteria(AchievementCriteriaTypes(i)); + UpdateAchievementCriteria(AchievementCriteriaTypes(i), 0, 0, 0, NULL, referencePlayer); } -static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = { 1057, 1107, 1108 }; +static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = {1057, 1107, 1108}; static const uint32 achievIdForDungeon[][4] = { // ach_cr_id, is_dungeon, is_raid, is_heroic_dungeon @@ -734,28 +1044,62 @@ static const uint32 achievIdForDungeon[][4] = { 0, false, false, false } }; +// Helper function to avoid having to specialize template for a 800 line long function +template <typename T> static bool IsGuild() { return false; } +template<> bool IsGuild<Guild>() { return true; } + /** * this function will be called whenever the user might have done a criteria relevant action */ -void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, Unit* unit /*= NULL*/) +template<class T> +void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit const* unit /*= NULL*/, Player* referencePlayer /*= NULL*/) { - TC_LOG_DEBUG("achievement", "AchievementMgr::UpdateAchievementCriteria(%u, %u, %u)", type, miscValue1, miscValue2); + if (type >= ACHIEVEMENT_CRITERIA_TYPE_TOTAL) + { + TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: Wrong criteria type %u", type); + return; + } + + if (!referencePlayer) + { + TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: Player is NULL! Cant update criteria"); + return; + } // disable for gamemasters with GM-mode enabled - if (m_player->IsGameMaster()) + if (referencePlayer->IsGameMaster()) + { + TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: [Player %s GM mode on] %s, %s (%u), " UI64FMTD ", " UI64FMTD ", " UI64FMTD + , referencePlayer->GetName().c_str(), GetLogNameForGuid(GetOwner()->GetGUID()), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2, miscValue3); return; + } - AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type); + TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: %s, %s (%u), " UI64FMTD ", " UI64FMTD ", " UI64FMTD + , GetLogNameForGuid(GetOwner()->GetGUID()), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2, miscValue3); + + // Lua_GetGuildLevelEnabled() is checked in achievement UI to display guild tab + if (IsGuild<T>() && !sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED)) + return; + + AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, IsGuild<T>()); for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) { AchievementCriteriaEntry const* achievementCriteria = (*i); - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->referredAchievement); + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->achievement); if (!achievement) + { + TC_LOG_ERROR("achievement", "UpdateAchievementCriteria: Achievement %u not found!", achievementCriteria->achievement); continue; + } - if (!CanUpdateCriteria(achievementCriteria, achievement)) + if (!CanUpdateCriteria(achievementCriteria, achievement, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) continue; + // requirements not found in the dbc + if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria)) + if (!data->Meets(referencePlayer, unit, miscValue1)) + continue; + switch (type) { // std. case: increment at 1 @@ -768,13 +1112,39 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: - case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_DEATH: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: + case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: + case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: + case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: + case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: + case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: + case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: + case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: + case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: + case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: + case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: + case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: + case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: + case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: + case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: + case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: + case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: + case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: + case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA + case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: + SetCriteriaProgress(achievementCriteria, 1, referencePlayer, PROGRESS_ACCUMULATE); break; - // std case: increment at miscvalue1 + // std case: increment at miscValue1 case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS: case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: @@ -785,116 +1155,44 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:/* FIXME: for online player only currently */ case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE); + case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: + case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: + case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: + SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); break; - // std case: high value at miscvalue1 + case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: + case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: + SetCriteriaProgress(achievementCriteria, miscValue2, referencePlayer, PROGRESS_ACCUMULATE); + break; + // std case: high value at miscValue1 case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID: case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT: case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST: case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST); - break; - - // specialized cases - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: - { - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - - if (achievement->categoryId == CATEGORY_CHILDRENS_WEEK) - { - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), NULL)) - continue; - } - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); break; - } - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - { - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - if (achievementCriteria->win_bg.bgMapID != GetPlayer()->GetMapId()) - continue; - - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) - continue; - - SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - { - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - if (achievementCriteria->kill_creature.creatureID != miscValue1) - continue; - - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) - continue; - - SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: - { - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue2) - continue; - - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit, miscValue1)) - continue; - - SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE); - break; - } case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: - if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria)) - if (!data->Meets(GetPlayer(), unit)) - continue; - SetCriteriaProgress(achievementCriteria, GetPlayer()->getLevel()); + SetCriteriaProgress(achievementCriteria, referencePlayer->getLevel(), referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: - // update at loading or specific skill update - if (miscValue1 && miscValue1 != achievementCriteria->reach_skill_level.skillID) - continue; - if (uint32 skillvalue = GetPlayer()->GetBaseSkillValue(achievementCriteria->reach_skill_level.skillID)) - SetCriteriaProgress(achievementCriteria, skillvalue); + if (uint32 skillvalue = referencePlayer->GetBaseSkillValue(achievementCriteria->reach_skill_level.skillID)) + SetCriteriaProgress(achievementCriteria, skillvalue, referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: - // update at loading or specific skill update - if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_level.skillID) - continue; - if (uint32 maxSkillvalue = GetPlayer()->GetPureMaxSkillValue(achievementCriteria->learn_skill_level.skillID)) - SetCriteriaProgress(achievementCriteria, maxSkillvalue); - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: - if (m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) != m_completedAchievements.end()) - SetCriteriaProgress(achievementCriteria, 1); + if (uint32 maxSkillvalue = referencePlayer->GetPureMaxSkillValue(achievementCriteria->learn_skill_level.skillID)) + SetCriteriaProgress(achievementCriteria, maxSkillvalue, referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: - { - SetCriteriaProgress(achievementCriteria, GetPlayer()->GetRewardedQuestCount()); + SetCriteriaProgress(achievementCriteria, referencePlayer->GetRewardedQuestCount(), referencePlayer); break; - } case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: { time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime(); @@ -904,7 +1202,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui { // reset if player missed one day. if (progress && progress->date < (nextDailyResetTime - 2 * DAY)) - SetCriteriaProgress(achievementCriteria, 0, PROGRESS_SET); + SetCriteriaProgress(achievementCriteria, 0, referencePlayer, PROGRESS_SET); continue; } @@ -913,7 +1211,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui // 1st time. Start count. progressType = PROGRESS_SET; else if (progress->date < (nextDailyResetTime - 2 * DAY)) - // last progress is older than 2 days. Player missed 1 day => Retart count. + // last progress is older than 2 days. Player missed 1 day => Restart count. progressType = PROGRESS_SET; else if (progress->date < (nextDailyResetTime - DAY)) // last progress is between 1 and 2 days. => 1st time of the day. @@ -922,462 +1220,54 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui // last progress is within the day before the reset => Already counted today. continue; - SetCriteriaProgress(achievementCriteria, 1, progressType); + SetCriteriaProgress(achievementCriteria, 1, referencePlayer, progressType); break; } case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: { - // speedup for non-login case - if (miscValue1 && miscValue1 != achievementCriteria->complete_quests_in_zone.zoneID) - continue; - uint32 counter = 0; - const RewardedQuestSet &rewQuests = GetPlayer()->getRewardedQuests(); + const RewardedQuestSet &rewQuests = referencePlayer->getRewardedQuests(); for (RewardedQuestSet::const_iterator itr = rewQuests.begin(); itr != rewQuests.end(); ++itr) { Quest const* quest = sObjectMgr->GetQuestTemplate(*itr); if (quest && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->complete_quests_in_zone.zoneID) ++counter; } - SetCriteriaProgress(achievementCriteria, counter); + SetCriteriaProgress(achievementCriteria, counter, referencePlayer); break; } - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - if (GetPlayer()->GetMapId() != achievementCriteria->complete_battleground.mapID) - continue; - SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - if (GetPlayer()->GetMapId() != achievementCriteria->death_at_map.mapID) - continue; - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_DEATH: - { - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - // skip wrong arena achievements, if not achievIdByArenaSlot then normal total death counter - bool notfit = false; - for (int j = 0; j < MAX_ARENA_SLOT; ++j) - { - if (achievIdByArenaSlot[j] == achievement->ID) - { - Battleground* bg = GetPlayer()->GetBattleground(); - if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j) - notfit = true; - - break; - } - } - if (notfit) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: - { - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - - Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : sMapMgr->FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId()); - if (!map || !map->IsDungeon()) - continue; - - // search case - bool found = false; - for (int j = 0; achievIdForDungeon[j][0]; ++j) - { - if (achievIdForDungeon[j][0] == achievement->ID) - { - if (map->IsRaid()) - { - // if raid accepted (ignore difficulty) - if (!achievIdForDungeon[j][2]) - break; // for - } - else if (GetPlayer()->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL) - { - // dungeon in normal mode accepted - if (!achievIdForDungeon[j][1]) - break; // for - } - else - { - // dungeon in heroic mode accepted - if (!achievIdForDungeon[j][3]) - break; // for - } - - found = true; - break; // for - } - } - if (!found) - continue; - - //FIXME: work only for instances where max == min for players - if (map->ToInstanceMap()->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit) - continue; - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - - } - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - if (miscValue1 != achievementCriteria->killed_by_creature.creatureEntry) - continue; - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - - // if team check required: must kill by opposition faction - if (achievement->ID == 318 && miscValue2 == GetPlayer()->GetTeam()) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: - { - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) - continue; - - // miscvalue1 is the ingame fallheight*100 as stored in dbc - SetCriteriaProgress(achievementCriteria, miscValue1); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - if (miscValue2 != achievementCriteria->death_from.type) - continue; - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + // miscValue1 is the ingame fallheight*100 as stored in dbc + SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: - { - // if miscvalues != 0, it contains the questID. - if (miscValue1) - { - if (miscValue1 != achievementCriteria->complete_quest.questID) - continue; - } - else - { - // login case. - if (!GetPlayer()->GetQuestRewardStatus(achievementCriteria->complete_quest.questID)) - continue; - } - - if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria)) - if (!data->Meets(GetPlayer(), unit)) - continue; - - SetCriteriaProgress(achievementCriteria, 1); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - { - if (!miscValue1 || miscValue1 != achievementCriteria->be_spell_target.spellID) - continue; - - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data) - continue; - - if (!data->Meets(GetPlayer(), unit)) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - { - if (!miscValue1 || miscValue1 != achievementCriteria->cast_spell.spellID) - continue; - - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data) - continue; - - if (!data->Meets(GetPlayer(), unit)) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: - if (miscValue1 && miscValue1 != achievementCriteria->learn_spell.spellID) - continue; - - if (GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID)) - SetCriteriaProgress(achievementCriteria, 1); - break; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: - { - // miscvalue1=loot_type (note: 0 = LOOT_CORPSE and then it ignored) - // miscvalue2=count of item loot - if (!miscValue1 || !miscValue2) - continue; - if (miscValue1 != achievementCriteria->loot_type.lootType) - continue; - - // zone specific - if (achievementCriteria->loot_type.lootTypeCount == 1) - { - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) - continue; - } - - SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: - // speedup for non-login case - if (miscValue1 && achievementCriteria->own_item.itemID != miscValue1) - continue; - SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: - if (!miscValue1) // no update at login - continue; - - // additional requirements - if (achievementCriteria->additionalRequirements[0].additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE) - { - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit, miscValue1)) - { - // reset the progress as we have a win without the requirement. - SetCriteriaProgress(achievementCriteria, 0); - continue; - } - } - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - - if (achievementCriteria->use_item.itemID != miscValue1) - continue; - - // Children's Week achievements have extra requirements - if (achievement->categoryId == CATEGORY_CHILDRENS_WEEK) - { - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), NULL)) - continue; - } - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: - // You _have_ to loot that item, just owning it when logging in does _not_ count! - if (!miscValue1) - continue; - if (miscValue1 != achievementCriteria->own_item.itemID) - continue; - SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE); - break; case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: - { - WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference); - if (!worldOverlayEntry) - break; - - bool matchFound = false; - for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j) - { - uint32 area_id = worldOverlayEntry->areatableID[j]; - if (!area_id) // array have 0 only in empty tail - break; - - int32 exploreFlag = GetAreaFlagByAreaID(area_id); - if (exploreFlag < 0) - continue; - - uint32 playerIndexOffset = uint32(exploreFlag) / 32; - uint32 mask = 1<< (uint32(exploreFlag) % 32); - - if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask) - { - matchFound = true; - break; - } - } - - if (matchFound) - SetCriteriaProgress(achievementCriteria, 1); + case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + SetCriteriaProgress(achievementCriteria, 1, referencePlayer); break; - } case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: - SetCriteriaProgress(achievementCriteria, GetPlayer()->GetBankBagSlotCount()); + SetCriteriaProgress(achievementCriteria, referencePlayer->GetBankBagSlotCount(), referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: { - // skip faction check only at loading - if (miscValue1 && miscValue1 != achievementCriteria->gain_reputation.factionID) - continue; - - int32 reputation = GetPlayer()->GetReputationMgr().GetReputation(achievementCriteria->gain_reputation.factionID); + int32 reputation = referencePlayer->GetReputationMgr().GetReputation(achievementCriteria->gain_reputation.factionID); if (reputation > 0) - SetCriteriaProgress(achievementCriteria, reputation); + SetCriteriaProgress(achievementCriteria, reputation, referencePlayer); break; } case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: - { - SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetExaltedFactionCount()); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: - { - // skip for login case - if (!miscValue1) - continue; - SetCriteriaProgress(achievementCriteria, 1); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: - { - // miscvalue1 = itemid - // miscvalue2 = itemSlot - if (!miscValue1) - continue; - - if (miscValue2 != achievementCriteria->equip_epic_item.itemSlot) - continue; - - // check item level and quality via achievement_criteria_data - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), 0, miscValue1)) - continue; - - SetCriteriaProgress(achievementCriteria, 1); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: - { - // miscvalue1 = itemid - // miscvalue2 = diced value - if (!miscValue1) - continue; - if (miscValue2 != achievementCriteria->roll_greed_on_loot.rollValue) - continue; - - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1); - if (!pProto) - continue; - - // check item level via achievement_criteria_data - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), 0, pProto->ItemLevel)) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: - { - // miscvalue1 = emote - if (!miscValue1) - continue; - if (miscValue1 != achievementCriteria->do_emote.emoteID) - continue; - if (achievementCriteria->do_emote.count) - { - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) - continue; - } - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: - case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: - { - if (!miscValue1) - continue; - - if (achievementCriteria->additionalRequirements[0].additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP) - { - if (GetPlayer()->GetMapId() != achievementCriteria->additionalRequirements[0].additionalRequirement_value) - continue; - - // map specific case (BG in fact) expected player targeted damage/heal - if (!unit || unit->GetTypeId() != TYPEID_PLAYER) - continue; - } - - SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: - // miscvalue1 = item_id - if (!miscValue1) - continue; - if (miscValue1 != achievementCriteria->equip_item.itemID) - continue; - - SetCriteriaProgress(achievementCriteria, 1); - break; - case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: - // miscvalue1 = go entry - if (!miscValue1) - continue; - if (miscValue1 != achievementCriteria->use_gameobject.goEntry) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: - if (!miscValue1) - continue; - if (miscValue1 != achievementCriteria->fish_in_gameobject.goEntry) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + SetCriteriaProgress(achievementCriteria, referencePlayer->GetReputationMgr().GetExaltedFactionCount(), referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: { - if (miscValue1 && miscValue1 != achievementCriteria->learn_skillline_spell.skillLine) - continue; - uint32 spellCount = 0; - for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin(); - spellIter != GetPlayer()->GetSpellMap().end(); + for (PlayerSpellMap::const_iterator spellIter = referencePlayer->GetSpellMap().begin(); + spellIter != referencePlayer->GetSpellMap().end(); ++spellIter) { SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first); @@ -1387,56 +1277,23 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui spellCount++; } } - SetCriteriaProgress(achievementCriteria, spellCount); + SetCriteriaProgress(achievementCriteria, spellCount, referencePlayer); break; } - case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - - if (achievementCriteria->win_duel.duelCount) - { - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data) - continue; - - if (!data->Meets(GetPlayer(), unit)) - continue; - } - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION: - SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetReveredFactionCount()); + SetCriteriaProgress(achievementCriteria, referencePlayer->GetReputationMgr().GetReveredFactionCount(), referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION: - SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetHonoredFactionCount()); + SetCriteriaProgress(achievementCriteria, referencePlayer->GetReputationMgr().GetHonoredFactionCount(), referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS: - SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetVisibleFactionCount()); + SetCriteriaProgress(achievementCriteria, referencePlayer->GetReputationMgr().GetVisibleFactionCount(), referencePlayer); break; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: - { - // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case - if (!miscValue1) - continue; - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(miscValue1); - if (!proto || proto->Quality < ITEM_QUALITY_EPIC) - continue; - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: { - if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_line.skillLine) - continue; - uint32 spellCount = 0; - for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin(); - spellIter != GetPlayer()->GetSpellMap().end(); + for (PlayerSpellMap::const_iterator spellIter = referencePlayer->GetSpellMap().begin(); + spellIter != referencePlayer->GetSpellMap().end(); ++spellIter) { SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter->first); @@ -1444,78 +1301,21 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (skillIter->second->skillId == achievementCriteria->learn_skill_line.skillLine) spellCount++; } - SetCriteriaProgress(achievementCriteria, spellCount); + SetCriteriaProgress(achievementCriteria, spellCount, referencePlayer); break; } case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL: - SetCriteriaProgress(achievementCriteria, GetPlayer()->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); - break; - case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: - if (!miscValue1 || miscValue1 != achievementCriteria->hk_class.classID) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: - if (!miscValue1 || miscValue1 != achievementCriteria->hk_race.raceID) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + SetCriteriaProgress(achievementCriteria, referencePlayer->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS), referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: - SetCriteriaProgress(achievementCriteria, GetPlayer()->GetMoney(), PROGRESS_HIGHEST); + SetCriteriaProgress(achievementCriteria, referencePlayer->GetMoney(), referencePlayer, PROGRESS_HIGHEST); break; case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: - { if (!miscValue1) - { - uint32 points = 0; - for (CompletedAchievementMap::iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) - if (AchievementEntry const* pAchievement = sAchievementMgr->GetAchievement(itr->first)) - points += pAchievement->points; - SetCriteriaProgress(achievementCriteria, points, PROGRESS_SET); - } + SetCriteriaProgress(achievementCriteria, _achievementPoints, referencePlayer, PROGRESS_SET); else - SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - { - if (!miscValue1 || miscValue1 != achievementCriteria->bg_objective.objectiveId) - continue; - - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); break; - } - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - { - // skip login update - if (!miscValue1) - continue; - - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: - { - if (!miscValue1 || miscValue1 != achievementCriteria->honorable_kill_at_area.areaID) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: { uint32 reqTeamType = achievementCriteria->highest_team_rating.teamtype; @@ -1525,13 +1325,13 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (miscValue2 != reqTeamType) continue; - SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST); + SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); } - else // login case + else // login case { for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) { - uint32 teamId = GetPlayer()->GetArenaTeamId(arena_slot); + uint32 teamId = referencePlayer->GetArenaTeamId(arena_slot); if (!teamId) continue; @@ -1539,7 +1339,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (!team || team->GetType() != reqTeamType) continue; - SetCriteriaProgress(achievementCriteria, team->GetStats().Rating, PROGRESS_HIGHEST); + SetCriteriaProgress(achievementCriteria, team->GetStats().Rating, referencePlayer, PROGRESS_HIGHEST); break; } } @@ -1555,13 +1355,13 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (miscValue2 != reqTeamType) continue; - SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST); + SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); } - else // login case + else // login case { for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) { - uint32 teamId = GetPlayer()->GetArenaTeamId(arena_slot); + uint32 teamId = referencePlayer->GetArenaTeamId(arena_slot); if (!teamId) continue; @@ -1569,69 +1369,57 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (!team || team->GetType() != reqTeamType) continue; - if (ArenaTeamMember const* member = team->GetMember(GetPlayer()->GetGUID())) + if (ArenaTeamMember const* member = team->GetMember(referencePlayer->GetGUID())) { - SetCriteriaProgress(achievementCriteria, member->PersonalRating, PROGRESS_HIGHEST); + SetCriteriaProgress(achievementCriteria, member->PersonalRating, referencePlayer, PROGRESS_HIGHEST); break; } } } - break; } - case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA - { - // Check map id requirement - if (miscValue1 == achievementCriteria->win_arena.mapID) - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } - case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: - { - // This criteria is only called directly after login - with expected miscvalue1 == 1 - if (!miscValue1) - continue; - - // They have no proper requirements in dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) - continue; - - SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); - break; - } - // std case: not exist in DBC, not triggered in code as result - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING: + case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: + SetCriteriaProgress(achievementCriteria, miscValue1, referencePlayer); break; // FIXME: not triggered in code as result, need to implement case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID: case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA: case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK: + case ACHIEVEMENT_CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS: + case ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD: + case ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL: + case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS: + case ACHIEVEMENT_CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: + case ACHIEVEMENT_CRITERIA_TYPE_REACH_BG_RATING: + case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD: + case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD: + case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: break; // Not implemented yet :( } if (IsCompletedCriteria(achievementCriteria, achievement)) - CompletedCriteriaFor(achievement); + CompletedCriteriaFor(achievement, referencePlayer); // check again the completeness for SUMM and REQ COUNT achievements, // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria if (achievement->flags & ACHIEVEMENT_FLAG_SUMM) if (IsCompletedAchievement(achievement)) - CompletedAchievement(achievement); + CompletedAchievement(achievement, referencePlayer); if (AchievementEntryList const* achRefList = sAchievementMgr->GetAchievementByReferencedId(achievement->ID)) for (AchievementEntryList::const_iterator itr = achRefList->begin(); itr != achRefList->end(); ++itr) if (IsCompletedAchievement(*itr)) - CompletedAchievement(*itr); + CompletedAchievement(*itr, referencePlayer); } } -bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement) +template<class T> +bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement) { if (!achievement) return false; @@ -1651,13 +1439,14 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve if (!progress) return false; - switch (achievementCriteria->requiredType) + switch (AchievementCriteriaTypes(achievementCriteria->type)) { case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: return progress->counter >= achievementCriteria->win_bg.winCount; case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: return progress->counter >= achievementCriteria->kill_creature.creatureCount; case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: + case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: return progress->counter >= achievementCriteria->reach_level.level; case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: return progress->counter >= achievementCriteria->reach_skill_level.skillLevel; @@ -1752,6 +1541,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve return progress->counter >= achievementCriteria->use_lfg.dungeonsComplete; case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: return progress->counter >= achievementCriteria->get_killing_blow.killCount; + case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: + return progress->counter >= achievementCriteria->currencyGain.count; case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: return achievementCriteria->win_arena.count && progress->counter >= achievementCriteria->win_arena.count; case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: @@ -1785,19 +1576,18 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED: case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER: - case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR: case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: default: break; } + return false; } -void AchievementMgr::CompletedCriteriaFor(AchievementEntry const* achievement) +template<class T> +void AchievementMgr<T>::CompletedCriteriaFor(AchievementEntry const* achievement, Player* referencePlayer) { // counter can never complete if (achievement->flags & ACHIEVEMENT_FLAG_COUNTER) @@ -1808,26 +1598,27 @@ void AchievementMgr::CompletedCriteriaFor(AchievementEntry const* achievement) return; if (IsCompletedAchievement(achievement)) - CompletedAchievement(achievement); + CompletedAchievement(achievement, referencePlayer); } -bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) +template<class T> +bool AchievementMgr<T>::IsCompletedAchievement(AchievementEntry const* entry) { // counter can never complete if (entry->flags & ACHIEVEMENT_FLAG_COUNTER) return false; // for achievement with referenced achievement criterias get from referenced and counter from self - uint32 achievmentForTestId = entry->refAchievement ? entry->refAchievement : entry->ID; - uint32 achievmentForTestCount = entry->count; + uint32 achievementForTestId = entry->refAchievement ? entry->refAchievement : entry->ID; + uint32 achievementForTestCount = entry->count; - AchievementCriteriaEntryList const* cList = sAchievementMgr->GetAchievementCriteriaByAchievement(achievmentForTestId); + AchievementCriteriaEntryList const* cList = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementForTestId); if (!cList) return false; - uint32 count = 0; + uint64 count = 0; // For SUMM achievements, we have to count the progress of each criteria of the achievement. - // Oddly, the target count is NOT countained in the achievement, but in each individual criteria + // Oddly, the target count is NOT contained in the achievement, but in each individual criteria if (entry->flags & ACHIEVEMENT_FLAG_SUMM) { for (AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr) @@ -1862,18 +1653,19 @@ bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) completed_all = false; // completed as have req. count of completed criterias - if (achievmentForTestCount > 0 && achievmentForTestCount <= count) + if (achievementForTestCount > 0 && achievementForTestCount <= count) return true; } // all criterias completed requirement - if (completed_all && achievmentForTestCount == 0) + if (completed_all && achievementForTestCount == 0) return true; return false; } -CriteriaProgress* AchievementMgr::GetCriteriaProgress(AchievementCriteriaEntry const* entry) +template<class T> +CriteriaProgress* AchievementMgr<T>::GetCriteriaProgress(AchievementCriteriaEntry const* entry) { CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID); @@ -1883,14 +1675,16 @@ CriteriaProgress* AchievementMgr::GetCriteriaProgress(AchievementCriteriaEntry c return &(iter->second); } -void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype) +template<class T> +void AchievementMgr<T>::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype) { // Don't allow to cheat - doing timed achievements without timer active TimedAchievementMap::iterator timedIter = m_timedAchievements.find(entry->ID); if (entry->timeLimit && timedIter == m_timedAchievements.end()) return; - TC_LOG_DEBUG("achievement", "AchievementMgr::SetCriteriaProgress(%u, %u) for (GUID:%u)", entry->ID, changeValue, m_player->GetGUIDLow()); + TC_LOG_DEBUG("achievement", "SetCriteriaProgress(%u, " UI64FMTD ") for (%s GUID: %u)", + entry->ID, changeValue, GetLogNameForGuid(GetOwner()->GetGUID()), GUID_LOPART(GetOwner()->GetGUID())); CriteriaProgress* progress = GetCriteriaProgress(entry); if (!progress) @@ -1905,7 +1699,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, } else { - uint32 newValue = 0; + uint64 newValue = 0; switch (ptype) { case PROGRESS_SET: @@ -1914,7 +1708,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, case PROGRESS_ACCUMULATE: { // avoid overflow - uint32 max_value = std::numeric_limits<uint32>::max(); + uint64 max_value = std::numeric_limits<uint64>::max(); newValue = max_value - progress->counter > changeValue ? progress->counter + changeValue : max_value; break; } @@ -1933,41 +1727,28 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, progress->changed = true; progress->date = time(NULL); // set the date to the latest update. + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(entry->achievement); uint32 timeElapsed = 0; - bool timedCompleted = false; + bool criteriaComplete = IsCompletedCriteria(entry, achievement); if (entry->timeLimit) { - // has to exist else we wouldn't be here - timedCompleted = IsCompletedCriteria(entry, sAchievementMgr->GetAchievement(entry->referredAchievement)); // Client expects this in packet timeElapsed = entry->timeLimit - (timedIter->second/IN_MILLISECONDS); // Remove the timer, we wont need it anymore - if (timedCompleted) + if (criteriaComplete) m_timedAchievements.erase(timedIter); } - SendCriteriaUpdate(entry, progress, timeElapsed, timedCompleted); -} - -void AchievementMgr::RemoveCriteriaProgress(AchievementCriteriaEntry const* entry) -{ - if (!entry) - return; + if (criteriaComplete && achievement->flags & ACHIEVEMENT_FLAG_SHOW_CRITERIA_MEMBERS && !progress->CompletedGUID) + progress->CompletedGUID = referencePlayer->GetGUID(); - CriteriaProgressMap::iterator criteriaProgress = m_criteriaProgress.find(entry->ID); - if (criteriaProgress == m_criteriaProgress.end()) - return; - - WorldPacket data(SMSG_CRITERIA_DELETED, 4); - data << uint32(entry->ID); - m_player->SendDirectMessage(&data); - - m_criteriaProgress.erase(criteriaProgress); + SendCriteriaUpdate(entry, progress, timeElapsed, criteriaComplete); } -void AchievementMgr::UpdateTimedAchievements(uint32 timeDiff) +template<class T> +void AchievementMgr<T>::UpdateTimedAchievements(uint32 timeDiff) { if (!m_timedAchievements.empty()) { @@ -1989,15 +1770,21 @@ void AchievementMgr::UpdateTimedAchievements(uint32 timeDiff) } } -void AchievementMgr::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost /*= 0*/) +template<class T> +void AchievementMgr<T>::StartTimedAchievement(AchievementCriteriaTimedTypes /*type*/, uint32 /*entry*/, uint32 /*timeLost = 0*/) +{ +} + +template<> +void AchievementMgr<Player>::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost /* = 0 */) { AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) { - if ((*i)->timerStartEvent != entry) + if ((*i)->timedCriteriaMiscId != entry) continue; - AchievementEntry const* achievement = sAchievementMgr->GetAchievement((*i)->referredAchievement); + AchievementEntry const* achievement = sAchievementMgr->GetAchievement((*i)->achievement); if (m_timedAchievements.find((*i)->ID) == m_timedAchievements.end() && !IsCompletedCriteria(*i, achievement)) { // Start the timer @@ -2006,18 +1793,19 @@ void AchievementMgr::StartTimedAchievement(AchievementCriteriaTimedTypes type, u m_timedAchievements[(*i)->ID] = (*i)->timeLimit * IN_MILLISECONDS - timeLost; // and at client too - SetCriteriaProgress(*i, 0, PROGRESS_SET); + SetCriteriaProgress(*i, 0, GetOwner(), PROGRESS_SET); } } } } -void AchievementMgr::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) +template<class T> +void AchievementMgr<T>::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry) { AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetTimedAchievementCriteriaByType(type); - for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i) + for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i) { - if ((*i)->timerStartEvent != entry) + if ((*i)->timedCriteriaMiscId != entry) continue; TimedAchievementMap::iterator timedIter = m_timedAchievements.find((*i)->ID); @@ -2033,19 +1821,26 @@ void AchievementMgr::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, } } -void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) +template<> +void AchievementMgr<Player>::CompletedAchievement(AchievementEntry const* achievement, Player* referencePlayer) { // disable for gamemasters with GM-mode enabled - if (m_player->IsGameMaster()) + if (GetOwner()->IsGameMaster()) return; if (achievement->flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID)) return; + if (achievement->flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_NEWS) + if (Guild* guild = referencePlayer->GetGuild()) + guild->AddGuildNews(GUILD_NEWS_PLAYER_ACHIEVEMENT, referencePlayer->GetGUID(), achievement->flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_HEADER, achievement->ID); + + if (!GetOwner()->GetSession()->PlayerLoading()) + SendAchievementEarned(achievement); + TC_LOG_INFO("achievement", "AchievementMgr::CompletedAchievement(%u). Player: %s (%u)", - achievement->ID, m_player->GetName().c_str(), m_player->GetGUIDLow()); + achievement->ID, GetOwner()->GetName().c_str(), GetOwner()->GetGUIDLow()); - SendAchievementEarned(achievement); CompletedAchievementData& ca = m_completedAchievements[achievement->ID]; ca.date = time(NULL); ca.changed = true; @@ -2055,8 +1850,10 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) if (!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) sAchievementMgr->SetRealmCompleted(achievement); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, achievement->points); + _achievementPoints += achievement->points; + + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, 0, 0, 0, NULL, referencePlayer); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, achievement->points, 0, 0, NULL, referencePlayer); // reward items and titles if any AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement); @@ -2070,9 +1867,9 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) //! Since no common attributes were found, (not even in titleRewardFlags field) //! we explicitly check by ID. Maybe in the future we could move the achievement_reward //! condition fields to the condition system. - if (uint32 titleId = reward->titleId[achievement->ID == 1793 ? GetPlayer()->getGender() : (GetPlayer()->GetTeam() == ALLIANCE ? 0 : 1)]) + if (uint32 titleId = reward->titleId[achievement->ID == 1793 ? GetOwner()->getGender() : (GetOwner()->GetTeam() == ALLIANCE ? 0 : 1)]) if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId)) - GetPlayer()->SetTitle(titleEntry); + GetOwner()->SetTitle(titleEntry); // mail if (reward->sender) @@ -2085,7 +1882,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) std::string subject = reward->subject; std::string text = reward->text; - int locIdx = GetPlayer()->GetSession()->GetSessionDbLocaleIndex(); + int locIdx = GetOwner()->GetSession()->GetSessionDbLocaleIndex(); if (locIdx >= 0) { if (AchievementRewardLocale const* loc = sAchievementMgr->GetAchievementRewardLocale(achievement)) @@ -2100,7 +1897,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) SQLTransaction trans = CharacterDatabase.BeginTransaction(); - Item* item = reward->itemId ? Item::CreateItem(reward->itemId, 1, GetPlayer()) : NULL; + Item* item = reward->itemId ? Item::CreateItem(reward->itemId, 1, GetOwner()) : NULL; if (item) { // save new item before send @@ -2110,74 +1907,391 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) draft.AddItem(item); } - draft.SendMailTo(trans, GetPlayer(), MailSender(MAIL_CREATURE, reward->sender)); + draft.SendMailTo(trans, GetOwner(), MailSender(MAIL_CREATURE, reward->sender)); CharacterDatabase.CommitTransaction(trans); } } -void AchievementMgr::SendAllAchievementData() const +template<> +void AchievementMgr<Guild>::CompletedAchievement(AchievementEntry const* achievement, Player* referencePlayer) { - WorldPacket data(SMSG_ALL_ACHIEVEMENT_DATA, m_completedAchievements.size()*8+4+m_criteriaProgress.size()*38+4); - BuildAllDataPacket(&data); - GetPlayer()->GetSession()->SendPacket(&data); + TC_LOG_DEBUG("achievement", "AchievementMgr<Guild>::CompletedAchievement(%u)", achievement->ID); + + if (achievement->flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID)) + return; + + if (achievement->flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_NEWS) + if (Guild* guild = referencePlayer->GetGuild()) + guild->AddGuildNews(GUILD_NEWS_GUILD_ACHIEVEMENT, 0, achievement->flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_HEADER, achievement->ID); + + SendAchievementEarned(achievement); + CompletedAchievementData& ca = m_completedAchievements[achievement->ID]; + ca.date = time(NULL); + ca.changed = true; + + if (achievement->flags & ACHIEVEMENT_FLAG_SHOW_GUILD_MEMBERS) + { + if (referencePlayer->GetGuildId() == GetOwner()->GetId()) + ca.guids.insert(referencePlayer->GetGUID()); + + if (Group const* group = referencePlayer->GetGroup()) + for (GroupReference const* ref = group->GetFirstMember(); ref != NULL; ref = ref->next()) + if (Player const* groupMember = ref->GetSource()) + if (groupMember->GetGuildId() == GetOwner()->GetId()) + ca.guids.insert(groupMember->GetGUID()); + } + + sAchievementMgr->SetRealmCompleted(achievement); + + _achievementPoints += achievement->points; + + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, 0, 0, 0, NULL, referencePlayer); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, achievement->points, 0, 0, NULL, referencePlayer); } -void AchievementMgr::SendRespondInspectAchievements(Player* player) const +struct VisibleAchievementPred +{ + bool operator()(CompletedAchievementMap::value_type const& val) + { + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(val.first); + return achievement && !(achievement->flags & ACHIEVEMENT_FLAG_HIDDEN); + } +}; + +template<class T> +void AchievementMgr<T>::SendAllAchievementData(Player* /*receiver*/) const { - WorldPacket data(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, 9+m_completedAchievements.size()*8+4+m_criteriaProgress.size()*38+4); - data.append(GetPlayer()->GetPackGUID()); - BuildAllDataPacket(&data); - player->GetSession()->SendPacket(&data); + VisibleAchievementPred isVisible; + size_t numCriteria = m_criteriaProgress.size(); + size_t numAchievements = std::count_if(m_completedAchievements.begin(), m_completedAchievements.end(), isVisible); + ByteBuffer criteriaData(numCriteria * (4 + 4 + 4 + 4 + 8 + 8)); + ObjectGuid guid = GetOwner()->GetGUID(); + ObjectGuid counter; + + WorldPacket data(SMSG_ALL_ACHIEVEMENT_DATA, 4 + numAchievements * (4 + 4) + 4 + numCriteria * (4 + 4 + 4 + 4 + 8 + 8)); + data.WriteBits(numCriteria, 21); + for (CriteriaProgressMap::const_iterator itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) + { + counter = itr->second.counter; + + data.WriteBit(guid[4]); + data.WriteBit(counter[3]); + data.WriteBit(guid[5]); + data.WriteBit(counter[0]); + data.WriteBit(counter[6]); + data.WriteBit(guid[3]); + data.WriteBit(guid[0]); + data.WriteBit(counter[4]); + data.WriteBit(guid[2]); + data.WriteBit(counter[7]); + data.WriteBit(guid[7]); + data.WriteBits(0u, 2); + data.WriteBit(guid[6]); + data.WriteBit(counter[2]); + data.WriteBit(counter[1]); + data.WriteBit(counter[5]); + data.WriteBit(guid[1]); + + criteriaData.WriteByteSeq(guid[3]); + criteriaData.WriteByteSeq(counter[5]); + criteriaData.WriteByteSeq(counter[6]); + criteriaData.WriteByteSeq(guid[4]); + criteriaData.WriteByteSeq(guid[6]); + criteriaData.WriteByteSeq(counter[2]); + criteriaData << uint32(0); // timer 2 + criteriaData.WriteByteSeq(guid[2]); + criteriaData << uint32(itr->first); // criteria id + criteriaData.WriteByteSeq(guid[5]); + criteriaData.WriteByteSeq(counter[0]); + criteriaData.WriteByteSeq(counter[3]); + criteriaData.WriteByteSeq(counter[1]); + criteriaData.WriteByteSeq(counter[4]); + criteriaData.WriteByteSeq(guid[0]); + criteriaData.WriteByteSeq(guid[7]); + criteriaData.WriteByteSeq(counter[7]); + criteriaData << uint32(0); // timer 1 + criteriaData.AppendPackedTime(itr->second.date); // criteria date + criteriaData.WriteByteSeq(guid[1]); + } + + data.WriteBits(numAchievements, 23); + data.FlushBits(); + data.append(criteriaData); + + for (CompletedAchievementMap::const_iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) + { + if (!isVisible(*itr)) + continue; + + data << uint32(itr->first); + data.AppendPackedTime(itr->second.date); + } + + SendPacket(&data); } -/** - * used by SMSG_RESPOND_INSPECT_ACHIEVEMENT and SMSG_ALL_ACHIEVEMENT_DATA - */ -void AchievementMgr::BuildAllDataPacket(WorldPacket* data) const +template<> +void AchievementMgr<Guild>::SendAllAchievementData(Player* receiver) const { - for (CompletedAchievementMap::const_iterator iter = m_completedAchievements.begin(); iter != m_completedAchievements.end(); ++iter) + VisibleAchievementPred isVisible; + WorldPacket data(SMSG_GUILD_ACHIEVEMENT_DATA, m_completedAchievements.size() * (4 + 4) + 3); + data.WriteBits(std::count_if(m_completedAchievements.begin(), m_completedAchievements.end(), isVisible), 23); + for (CompletedAchievementMap::const_iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) { - // Skip hidden achievements - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(iter->first); - if (!achievement || achievement->flags & ACHIEVEMENT_FLAG_HIDDEN) + if (!isVisible(*itr)) continue; - *data << uint32(iter->first); - data->AppendPackedTime(iter->second.date); + data.AppendPackedTime(itr->second.date); + data << uint32(itr->first); } - *data << int32(-1); - for (CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter != m_criteriaProgress.end(); ++iter) + receiver->GetSession()->SendPacket(&data); +} + +template<> +void AchievementMgr<Player>::SendAchievementInfo(Player* receiver, uint32 /*achievementId = 0 */) const +{ + ObjectGuid guid = GetOwner()->GetGUID(); + ObjectGuid counter; + + VisibleAchievementPred isVisible; + size_t numCriteria = m_criteriaProgress.size(); + size_t numAchievements = std::count_if(m_completedAchievements.begin(), m_completedAchievements.end(), isVisible); + ByteBuffer criteriaData(numCriteria * 16); + + WorldPacket data(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, 1 + 8 + 3 + 3 + numAchievements * (4 + 4) + numCriteria * (0)); + data.WriteBit(guid[7]); + data.WriteBit(guid[4]); + data.WriteBit(guid[1]); + data.WriteBits(numAchievements, 23); + data.WriteBit(guid[0]); + data.WriteBit(guid[3]); + data.WriteBits(numCriteria, 21); + data.WriteBit(guid[2]); + for (CriteriaProgressMap::const_iterator itr = m_criteriaProgress.begin(); itr != m_criteriaProgress.end(); ++itr) + { + counter = itr->second.counter; + + data.WriteBit(counter[5]); + data.WriteBit(counter[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[4]); + data.WriteBit(guid[2]); + data.WriteBit(counter[6]); + data.WriteBit(guid[0]); + data.WriteBit(counter[4]); + data.WriteBit(counter[1]); + data.WriteBit(counter[2]); + data.WriteBit(guid[3]); + data.WriteBit(guid[7]); + data.WriteBits(0, 2); // criteria progress flags + data.WriteBit(counter[0]); + data.WriteBit(guid[5]); + data.WriteBit(guid[6]); + data.WriteBit(counter[7]); + + criteriaData.WriteByteSeq(guid[3]); + criteriaData.WriteByteSeq(counter[4]); + criteriaData << uint32(0); // timer 1 + criteriaData.WriteByteSeq(guid[1]); + criteriaData.AppendPackedTime(itr->second.date); + criteriaData.WriteByteSeq(counter[3]); + criteriaData.WriteByteSeq(counter[7]); + criteriaData.WriteByteSeq(guid[5]); + criteriaData.WriteByteSeq(counter[0]); + criteriaData.WriteByteSeq(guid[4]); + criteriaData.WriteByteSeq(guid[2]); + criteriaData.WriteByteSeq(guid[6]); + criteriaData.WriteByteSeq(guid[7]); + criteriaData.WriteByteSeq(counter[6]); + criteriaData << uint32(itr->first); + criteriaData << uint32(0); // timer 2 + criteriaData.WriteByteSeq(counter[1]); + criteriaData.WriteByteSeq(counter[5]); + criteriaData.WriteByteSeq(guid[0]); + criteriaData.WriteByteSeq(counter[2]); + } + + data.WriteBit(guid[6]); + data.WriteBit(guid[5]); + data.FlushBits(); + data.append(criteriaData); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[2]); + + for (CompletedAchievementMap::const_iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr) + { + if (!isVisible(*itr)) + continue; + + data << uint32(itr->first); + data.AppendPackedTime(itr->second.date); + } + + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[5]); + + receiver->GetSession()->SendPacket(&data); +} + +template<> +void AchievementMgr<Guild>::SendAchievementInfo(Player* receiver, uint32 achievementId /*= 0*/) const +{ + //will send response to criteria progress request + AchievementCriteriaEntryList const* criteria = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementId); + if (!criteria) + { + // send empty packet + WorldPacket data(SMSG_GUILD_CRITERIA_DATA, 3); + data.WriteBits(0, 21); + receiver->GetSession()->SendPacket(&data); + return; + } + + ObjectGuid counter; + ObjectGuid guid; + uint32 numCriteria = 0; + ByteBuffer criteriaData(criteria->size() * (8 + 8 + 4 + 4 + 4)); + ByteBuffer criteriaBits(criteria->size() * (8 + 8) / 8); + for (AchievementCriteriaEntryList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr) + { + uint32 criteriaId = (*itr)->ID; + CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(criteriaId); + if (progress == m_criteriaProgress.end()) + continue; + + ++numCriteria; + } + + criteriaBits.WriteBits(numCriteria, 21); + + for (AchievementCriteriaEntryList::const_iterator itr = criteria->begin(); itr != criteria->end(); ++itr) { - *data << uint32(iter->first); - data->appendPackGUID(iter->second.counter); - data->append(GetPlayer()->GetPackGUID()); - *data << uint32(0); - data->AppendPackedTime(iter->second.date); - *data << uint32(0); - *data << uint32(0); + uint32 criteriaId = (*itr)->ID; + CriteriaProgressMap::const_iterator progress = m_criteriaProgress.find(criteriaId); + if (progress == m_criteriaProgress.end()) + continue; + + counter = progress->second.counter; + guid = progress->second.CompletedGUID; + + criteriaBits.WriteBit(counter[4]); + criteriaBits.WriteBit(counter[1]); + criteriaBits.WriteBit(guid[2]); + criteriaBits.WriteBit(counter[3]); + criteriaBits.WriteBit(guid[1]); + criteriaBits.WriteBit(counter[5]); + criteriaBits.WriteBit(counter[0]); + criteriaBits.WriteBit(guid[3]); + criteriaBits.WriteBit(counter[2]); + criteriaBits.WriteBit(guid[7]); + criteriaBits.WriteBit(guid[5]); + criteriaBits.WriteBit(guid[0]); + criteriaBits.WriteBit(counter[6]); + criteriaBits.WriteBit(guid[6]); + criteriaBits.WriteBit(counter[7]); + criteriaBits.WriteBit(guid[4]); + + criteriaData.WriteByteSeq(guid[5]); + criteriaData << uint32(progress->second.date); // unknown date + criteriaData.WriteByteSeq(counter[3]); + criteriaData.WriteByteSeq(counter[7]); + criteriaData << uint32(progress->second.date); // unknown date + criteriaData.WriteByteSeq(counter[6]); + criteriaData.WriteByteSeq(guid[4]); + criteriaData.WriteByteSeq(guid[1]); + criteriaData.WriteByteSeq(counter[4]); + criteriaData.WriteByteSeq(guid[3]); + criteriaData.WriteByteSeq(counter[0]); + criteriaData.WriteByteSeq(guid[2]); + criteriaData.WriteByteSeq(counter[1]); + criteriaData.WriteByteSeq(guid[6]); + criteriaData << uint32(progress->second.date); // last update time (not packed!) + criteriaData << uint32(criteriaId); + criteriaData.WriteByteSeq(counter[5]); + criteriaData << uint32(0); + criteriaData.WriteByteSeq(guid[7]); + criteriaData.WriteByteSeq(counter[2]); + criteriaData.WriteByteSeq(guid[0]); } - *data << int32(-1); + WorldPacket data(SMSG_GUILD_CRITERIA_DATA, criteriaBits.size() + criteriaData.size()); + data.append(criteriaBits); + if (numCriteria) + data.append(criteriaData); + + receiver->GetSession()->SendPacket(&data); } -bool AchievementMgr::HasAchieved(uint32 achievementId) const +template<class T> +bool AchievementMgr<T>::HasAchieved(uint32 achievementId) const { return m_completedAchievements.find(achievementId) != m_completedAchievements.end(); } -bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement) +template<class T> +bool AchievementMgr<T>::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) { if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, NULL)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Disabled", + criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + return false; + } + + if (achievement->mapID != -1 && referencePlayer->GetMapId() != uint32(achievement->mapID)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Wrong map", + criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + return false; + } + + if ((achievement->requiredFaction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) || + (achievement->requiredFaction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Wrong faction", + criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); return false; + } - if (achievement->mapID != -1 && GetPlayer()->GetMapId() != uint32(achievement->mapID)) + if (IsCompletedCriteria(criteria, achievement)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Is Completed", + criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); return false; + } - if ((achievement->requiredFaction == ACHIEVEMENT_FACTION_HORDE && GetPlayer()->GetTeam() != HORDE) || - (achievement->requiredFaction == ACHIEVEMENT_FACTION_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE)) + if (!RequirementsSatisfied(criteria, miscValue1, miscValue2, miscValue3, unit, referencePlayer)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Requirements not satisfied", + criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); return false; + } + if (!AdditionalRequirementsSatisfied(criteria, miscValue1, miscValue2, unit, referencePlayer)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Additional requirements not satisfied", + criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + return false; + } + + if (!ConditionsSatisfied(criteria, referencePlayer)) + { + TC_LOG_TRACE("achievement", "CanUpdateCriteria: %s (Id: %u Type %s) Conditions not satisfied", + criteria->name, criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->type)); + return false; + } + + return true; +} + +template<class T> +bool AchievementMgr<T>::ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const +{ for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i) { if (!criteria->additionalRequirements[i].additionalRequirement_type) @@ -2186,11 +2300,11 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, switch (criteria->additionalRequirements[i].additionalRequirement_type) { case ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP: - if (GetPlayer()->GetMapId() != criteria->additionalRequirements[i].additionalRequirement_value) + if (referencePlayer->GetMapId() != criteria->additionalRequirements[i].additionalRequirement_value) return false; break; case ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP: - if (GetPlayer()->GetGroup()) + if (referencePlayer->GetGroup()) return false; break; default: @@ -2198,13 +2312,739 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, } } - // don't update already completed criteria - if (IsCompletedCriteria(criteria, achievement)) - return false; + return true; +} +template<class T> +bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const +{ + switch (AchievementCriteriaTypes(achievementCriteria->type)) + { + case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: + case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION: + case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: + case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: + case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: + case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: + case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL: + case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: + case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS: + case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: + case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: + case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED: + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED: + case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: + case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: + case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: + case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: + case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: + case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: + if (!miscValue1) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: + case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: + case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION: + case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: + case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS: + case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: + case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: + break; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + if (m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) == m_completedAchievements.end()) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: + if (!miscValue1 || achievementCriteria->win_bg.bgMapID != referencePlayer->GetMapId()) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: + if (!miscValue1 || achievementCriteria->kill_creature.creatureID != miscValue1) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: + // update at loading or specific skill update + if (miscValue1 && miscValue1 != achievementCriteria->reach_skill_level.skillID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: + // update at loading or specific skill update + if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_level.skillID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: + if (miscValue1 && miscValue1 != achievementCriteria->complete_quests_in_zone.zoneID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: + if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->complete_battleground.mapID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: + if (!miscValue1 || referencePlayer->GetMapId() != achievementCriteria->death_at_map.mapID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_DEATH: + { + if (!miscValue1) + return false; + // skip wrong arena achievements, if not achievIdByArenaSlot then normal total death counter + bool notfit = false; + for (int j = 0; j < MAX_ARENA_SLOT; ++j) + { + if (achievIdByArenaSlot[j] == achievementCriteria->achievement) + { + Battleground* bg = referencePlayer->GetBattleground(); + if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j) + notfit = true; + break; + } + } + if (notfit) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: + { + if (!miscValue1) + return false; + + Map const* map = referencePlayer->IsInWorld() ? referencePlayer->GetMap() : sMapMgr->FindMap(referencePlayer->GetMapId(), referencePlayer->GetInstanceId()); + if (!map || !map->IsDungeon()) + return false; + + // search case + bool found = false; + for (int j = 0; achievIdForDungeon[j][0]; ++j) + { + if (achievIdForDungeon[j][0] == achievementCriteria->achievement) + { + if (map->IsRaid()) + { + // if raid accepted (ignore difficulty) + if (!achievIdForDungeon[j][2]) + break; // for + } + else if (referencePlayer->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL) + { + // dungeon in normal mode accepted + if (!achievIdForDungeon[j][1]) + break; // for + } + else + { + // dungeon in heroic mode accepted + if (!achievIdForDungeon[j][3]) + break; // for + } + + found = true; + break; // for + } + } + if (!found) + return false; + + //FIXME: work only for instances where max == min for players + if (((InstanceMap*)map)->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: + if (!miscValue1 || miscValue1 != achievementCriteria->killed_by_creature.creatureEntry) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: + if (!miscValue1 || !unit || unit->GetTypeId() != TYPEID_PLAYER) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: + if (!miscValue1 || miscValue2 != achievementCriteria->death_from.type) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: + { + // if miscValues != 0, it contains the questID. + if (miscValue1) + { + if (miscValue1 != achievementCriteria->complete_quest.questID) + return false; + } + else + { + // login case. + if (!referencePlayer->GetQuestRewardStatus(achievementCriteria->complete_quest.questID)) + return false; + } + + if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria)) + if (!data->Meets(referencePlayer, unit)) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: + case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: + if (!miscValue1 || miscValue1 != achievementCriteria->be_spell_target.spellID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: + if (!miscValue1 || miscValue1 != achievementCriteria->cast_spell.spellID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: + if (miscValue1 && miscValue1 != achievementCriteria->learn_spell.spellID) + return false; + + if (!referencePlayer->HasSpell(achievementCriteria->learn_spell.spellID)) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: + // miscValue1 = itemId - miscValue2 = count of item loot + // miscValue3 = loot_type (note: 0 = LOOT_CORPSE and then it ignored) + if (!miscValue1 || !miscValue2 || !miscValue3 || miscValue3 != achievementCriteria->loot_type.lootType) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: + if (miscValue1 && achievementCriteria->own_item.itemID != miscValue1) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: + if (!miscValue1 || achievementCriteria->use_item.itemID != miscValue1) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: + if (!miscValue1 || miscValue1 != achievementCriteria->own_item.itemID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: + { + WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference); + if (!worldOverlayEntry) + break; + + bool matchFound = false; + for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j) + { + uint32 area_id = worldOverlayEntry->areatableID[j]; + if (!area_id) // array have 0 only in empty tail + break; + + int32 exploreFlag = GetAreaFlagByAreaID(area_id); + if (exploreFlag < 0) + continue; + + uint32 playerIndexOffset = uint32(exploreFlag) / 32; + uint32 mask = 1 << (uint32(exploreFlag) % 32); + + if (referencePlayer->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask) + { + matchFound = true; + break; + } + } + + if (!matchFound) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: + if (miscValue1 && miscValue1 != achievementCriteria->gain_reputation.factionID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: + // miscValue1 = itemid miscValue2 = itemSlot + if (!miscValue1 || miscValue2 != achievementCriteria->equip_epic_item.itemSlot) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: + { + // miscValue1 = itemid miscValue2 = diced value + if (!miscValue1 || miscValue2 != achievementCriteria->roll_greed_on_loot.rollValue) + return false; + + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1)); + if (!proto) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: + if (!miscValue1 || miscValue1 != achievementCriteria->do_emote.emoteID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: + case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: + if (!miscValue1) + return false; + + if (achievementCriteria->additionalRequirements[0].additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP) + { + if (referencePlayer->GetMapId() != achievementCriteria->additionalRequirements[0].additionalRequirement_value) + return false; + + // map specific case (BG in fact) expected player targeted damage/heal + if (!unit || unit->GetTypeId() != TYPEID_PLAYER) + return false; + } + break; + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: + // miscValue1 = item_id + if (!miscValue1 || miscValue1 != achievementCriteria->equip_item.itemID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: + if (!miscValue1 || miscValue1 != achievementCriteria->use_gameobject.goEntry) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: + if (!miscValue1 || miscValue1 != achievementCriteria->fish_in_gameobject.goEntry) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: + if (miscValue1 && miscValue1 != achievementCriteria->learn_skillline_spell.skillLine) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: + { + if (!miscValue1) + return false; + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(uint32(miscValue1)); + if (!proto || proto->Quality < ITEM_QUALITY_EPIC) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: + if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_line.skillLine) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: + if (!miscValue1 || miscValue1 != achievementCriteria->hk_class.classID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: + if (!miscValue1 || miscValue1 != achievementCriteria->hk_race.raceID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: + if (!miscValue1 || miscValue1 != achievementCriteria->bg_objective.objectiveId) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: + if (!miscValue1 || miscValue1 != achievementCriteria->honorable_kill_at_area.areaID) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: + if (!miscValue1 || !miscValue2 || int64(miscValue2) < 0 + || miscValue1 != achievementCriteria->currencyGain.currency) + return false; + break; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: + if (miscValue1 != achievementCriteria->win_arena.mapID) + return false; + break; + default: + break; + } return true; } +template<class T> +bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 /*miscValue2*/, Unit const* unit, Player* referencePlayer) const +{ + for (uint8 i = 0; i < MAX_ADDITIONAL_CRITERIA_CONDITIONS; ++i) + { + uint32 reqType = criteria->additionalConditionType[i]; + uint32 reqValue = criteria->additionalConditionValue[i]; + + switch (AchievementCriteriaAdditionalCondition(reqType)) + { + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY: // 4 + if (!unit || unit->GetEntry() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER: // 5 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD: // 6 + if (!unit || unit->IsAlive()) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY: // 7 + if (!unit || !referencePlayer->IsHostileTo(unit)) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA: // 8 + if (!referencePlayer->HasAura(reqValue)) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA: // 10 + if (!unit || !unit->HasAura(reqValue)) + return false; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE: // 11 + if (!unit || !unit->HasAuraType(AuraType(reqValue))) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN: // 14 + { + // miscValue1 is itemid + ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); + if (!item || item->Quality < reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS: // 15 + { + // miscValue1 is itemid + ItemTemplate const* const item = sObjectMgr->GetItemTemplate(uint32(miscValue1)); + if (!item || item->Quality != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE: // 17 + { + uint32 zoneId, areaId; + referencePlayer->GetZoneAndAreaId(zoneId, areaId); + if (zoneId != reqValue && areaId != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE: // 18 + { + if (!unit) + return false; + uint32 zoneId, areaId; + unit->GetZoneAndAreaId(zoneId, areaId); + if (zoneId != reqValue && areaId != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY: // 20 + if (uint32(referencePlayer->GetMap()->GetDifficulty()) != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE: // 25 + if (referencePlayer->getRace() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS: // 26 + if (referencePlayer->getClass() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE: // 27 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getRace() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS: // 28 + if (!unit || unit->GetTypeId() != TYPEID_PLAYER || unit->getClass() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS: // 29 + if (referencePlayer->GetGroup() && referencePlayer->GetGroup()->GetMembersCount() >= reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE: // 30 + { + if (!unit) + return false; + Creature const* const creature = unit->ToCreature(); + if (!creature || creature->GetCreatureType() != reqValue) + return false; + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP: // 32 + if (referencePlayer->GetMapId() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX: // 38 + // miscValue1 is title's bit index + if (miscValue1 != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL: // 39 + if (referencePlayer->getLevel() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL: // 40 + if (!unit || unit->getLevel() != reqValue) + return false; + break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE: // 41 + if (!unit || unit->GetZoneId() != reqValue) + return false; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW: // 46 + if (!unit || unit->GetHealthPct() >= reqValue) + return false; + break; + default: + break; + } + } + return true; +} + +char const* AchievementGlobalMgr::GetCriteriaTypeString(uint32 type) +{ + return GetCriteriaTypeString(AchievementCriteriaTypes(type)); +} + +char const* AchievementGlobalMgr::GetCriteriaTypeString(AchievementCriteriaTypes type) +{ + switch (type) + { + case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: + return "KILL_CREATURE"; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: + return "TYPE_WIN_BG"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS: + return "COMPLETE_RESEARCH"; + case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: + return "REACH_LEVEL"; + case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: + return "REACH_SKILL_LEVEL"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + return "COMPLETE_ACHIEVEMENT"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT: + return "COMPLETE_QUEST_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: + return "COMPLETE_DAILY_QUEST_DAILY"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: + return "COMPLETE_QUESTS_IN_ZONE"; + case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: + return "CURRENCY"; + case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE: + return "DAMAGE_DONE"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: + return "COMPLETE_DAILY_QUEST"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: + return "COMPLETE_BATTLEGROUND"; + case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: + return "DEATH_AT_MAP"; + case ACHIEVEMENT_CRITERIA_TYPE_DEATH: + return "DEATH"; + case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON: + return "DEATH_IN_DUNGEON"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID: + return "COMPLETE_RAID"; + case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE: + return "KILLED_BY_CREATURE"; + case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER: + return "KILLED_BY_PLAYER"; + case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: + return "FALL_WITHOUT_DYING"; + case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM: + return "DEATHS_FROM"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: + return "COMPLETE_QUEST"; + case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: + return "BE_SPELL_TARGET"; + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: + return "CAST_SPELL"; + case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: + return "BG_OBJECTIVE_CAPTURE"; + case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA: + return "HONORABLE_KILL_AT_AREA"; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: + return "WIN_ARENA"; + case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA: + return "PLAY_ARENA"; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: + return "LEARN_SPELL"; + case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: + return "HONORABLE_KILL"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: + return "OWN_ITEM"; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: + return "WIN_RATED_ARENA"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING: + return "HIGHEST_TEAM_RATING"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING: + return "HIGHEST_PERSONAL_RATING"; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: + return "LEARN_SKILL_LEVEL"; + case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: + return "USE_ITEM"; + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: + return "LOOT_ITEM"; + case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: + return "EXPLORE_AREA"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK: + return "OWN_RANK"; + case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: + return "BUY_BANK_SLOT"; + case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: + return "GAIN_REPUTATION"; + case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION: + return "GAIN_EXALTED_REPUTATION"; + case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP: + return "VISIT_BARBER_SHOP"; + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: + return "EQUIP_EPIC_ITEM"; + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: + return "ROLL_NEED_ON_LOOT"; + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: + return "GREED_ON_LOOT"; + case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: + return "HK_CLASS"; + case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: + return "HK_RACE"; + case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: + return "DO_EMOTE"; + case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: + return "HEALING_DONE"; + case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: + return "GET_KILLING_BLOWS"; + case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: + return "EQUIP_ITEM"; + case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS: + return "MONEY_FROM_VENDORS"; + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS: + return "GOLD_SPENT_FOR_TALENTS"; + case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: + return "NUMBER_OF_TALENT_RESETS"; + case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: + return "MONEY_FROM_QUEST_REWARD"; + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING: + return "GOLD_SPENT_FOR_TRAVELLING"; + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER: + return "GOLD_SPENT_AT_BARBER"; + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL: + return "GOLD_SPENT_FOR_MAIL"; + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: + return "LOOT_MONEY"; + case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT: + return "USE_GAMEOBJECT"; + case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: + return "BE_SPELL_TARGET2"; + case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: + return "SPECIAL_PVP_KILL"; + case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT: + return "FISH_IN_GAMEOBJECT"; + case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: + return "ON_LOGIN"; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: + return "LEARN_SKILLLINE_SPELLS"; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: + return "WIN_DUEL"; + case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL: + return "LOSE_DUEL"; + case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: + return "KILL_CREATURE_TYPE"; + case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: + return "GOLD_EARNED_BY_AUCTIONS"; + case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION: + return "CREATE_AUCTION"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID: + return "HIGHEST_AUCTION_BID"; + case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: + return "WON_AUCTIONS"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: + return "HIGHEST_AUCTION_SOLD"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED: + return "HIGHEST_GOLD_VALUE_OWNED"; + case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION: + return "GAIN_REVERED_REPUTATION"; + case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION: + return "GAIN_HONORED_REPUTATION"; + case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS: + return "KNOWN_FACTIONS"; + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: + return "LOOT_EPIC_ITEM"; + case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: + return "RECEIVE_EPIC_ITEM"; + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED: + return "ROLL_NEED"; + case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED: + return "ROLL_GREED"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT: + return "HIT_DEALT"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: + return "HIT_RECEIVED"; + case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED: + return "TOTAL_DAMAGE_RECEIVED"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST: + return "HIGHEST_HEAL_CAST"; + case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED: + return "TOTAL_HEALING_RECEIVED"; + case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: + return "HIGHEST_HEALING_RECEIVED"; + case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: + return "QUEST_ABANDONED"; + case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: + return "FLIGHT_PATHS_TAKEN"; + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: + return "LOOT_TYPE"; + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: + return "CAST_SPELL2"; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE: + return "LEARN_SKILL_LINE"; + case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL: + return "EARN_HONORABLE_KILL"; + case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: + return "ACCEPTED_SUMMONINGS"; + case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: + return "EARN_ACHIEVEMENT_POINTS"; + case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: + return "USE_LFD_TO_GROUP_WITH_PLAYERS"; + case ACHIEVEMENT_CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS: + return "SPENT_GOLD_GUILD_REPAIRS"; + case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL: + return "REACH_GUILD_LEVEL"; + case ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD: + return "CRAFT_ITEMS_GUILD"; + case ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL: + return "CATCH_FROM_POOL"; + case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS: + return "BUY_GUILD_BANK_SLOTS"; + case ACHIEVEMENT_CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS: + return "EARN_GUILD_ACHIEVEMENT_POINTS"; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: + return "WIN_RATED_BATTLEGROUND"; + case ACHIEVEMENT_CRITERIA_TYPE_REACH_BG_RATING: + return "REACH_BG_RATING"; + case ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD: + return "BUY_GUILD_TABARD"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD: + return "COMPLETE_QUESTS_GUILD"; + case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD: + return "HONORABLE_KILLS_GUILD"; + case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD: + return "KILL_CREATURE_TYPE_GUILD"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE: + return "GUILD_CHALLENGE_TYPE"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: + return "GUILD_CHALLENGE"; + } + return "MISSING_TYPE"; +} + +template class AchievementMgr<Guild>; +template class AchievementMgr<Player>; + //========================================================== void AchievementGlobalMgr::LoadAchievementCriteriaList() { @@ -2216,23 +3056,28 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() return; } - uint32 loaded = 0; + uint32 criterias = 0; + uint32 guildCriterias = 0; for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId) { AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(entryId); if (!criteria) continue; - m_AchievementCriteriasByType[criteria->requiredType].push_back(criteria); - m_AchievementCriteriaListByAchievement[criteria->referredAchievement].push_back(criteria); + AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->achievement); - if (criteria->timeLimit) - m_AchievementCriteriasByTimedType[criteria->timedType].push_back(criteria); + m_AchievementCriteriaListByAchievement[criteria->achievement].push_back(criteria); + + if (achievement && achievement->flags & ACHIEVEMENT_FLAG_GUILD) + ++guildCriterias, m_GuildAchievementCriteriasByType[criteria->type].push_back(criteria); + else + ++criterias, m_AchievementCriteriasByType[criteria->type].push_back(criteria); - ++loaded; + if (criteria->timeLimit) + m_AchievementCriteriasByTimedType[criteria->timedCriteriaStartType].push_back(criteria); } - TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria in %u ms", loaded, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria and %u guild achievement crieteria in %u ms", criterias, guildCriterias, GetMSTimeDiffToNow(oldMSTime)); } void AchievementGlobalMgr::LoadAchievementReferenceList() @@ -2322,79 +3167,6 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() } while (result->NextRow()); - // post loading checks - for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId) - { - AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(entryId); - if (!criteria) - continue; - - switch (criteria->requiredType) - { - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: - case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: - case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: - case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: - case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: - case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: - case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL: - case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: - case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: - case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: - // achievement requires db data - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: - { - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->referredAchievement); - if (!achievement) - continue; - - // exist many achievements with this criteria, use at this moment hardcoded check to skil simple case - if (achievement->ID == 1282) - break; - - continue; - } - case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: // need skip generic cases - if (criteria->additionalRequirements[0].additionalRequirement_type != ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE) - continue; - break; - case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: // need skip generic cases - if (criteria->do_emote.count == 0) - continue; - break; - case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: // skip statistics - if (criteria->win_duel.duelCount == 0) - continue; - break; - case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: // need skip generic cases - if (criteria->loot_type.lootTypeCount != 1) - continue; - break; - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: - case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements - { - AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->referredAchievement); - if (!achievement) - continue; - if (achievement->categoryId != CATEGORY_CHILDRENS_WEEK) - continue; - break; - } - default: // type not use DB data, ignore - continue; - } - - if (!GetCriteriaDataSet(criteria) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, entryId, NULL)) - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` does not have expected data for criteria (Entry: %u Type: %u) for achievement %u.", criteria->ID, criteria->requiredType, criteria->referredAchievement); - } - TC_LOG_INFO("server.loading", ">> Loaded %u additional achievement criteria data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 219a8fd52fb..efa3e3ce5fa 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -39,26 +39,25 @@ typedef std::unordered_map<uint32, AchievementEntryList> AchievementList struct CriteriaProgress { - uint32 counter; + uint64 counter; time_t date; // latest update time. + uint64 CompletedGUID; // GUID of the player that completed this criteria (guild achievements) bool changed; }; enum AchievementCriteriaDataType -{ // value1 value2 comment - ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0 - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1, // creature_id 0 - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2, // class_id race_id - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH= 3, // health_percent 0 - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD = 4, // own_team 0 not corpse (not released body), own_team == false if enemy team expected - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5, // spell_id effect_idx - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6, // area id 0 - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx - ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target +{ // value1 value2 comment + ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0 + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1, // creature_id 0 + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2, // class_id race_id + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH= 3, // health_percent 0 + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5, // spell_id effect_idx + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx + ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10, // gender 0=male; 1=female ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT = 11, // scripted requirement - ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12, // difficulty normal/heroic difficulty for current event map + // REUSE ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13, // count "with less than %u people in the zone" ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14, // team HORDE(67), ALLIANCE(469) ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK = 15, // drunken_state 0 (enum DrunkenState) of player @@ -68,11 +67,12 @@ enum AchievementCriteriaDataType ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19, // item_level item_quality for equipped item in slot to check item level and quality ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID = 20, // map_id 0 player must be on map with id in map_id ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21, // class_id race_id - ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY = 22, // N login on day of N-th Birthday - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23 // title_id known (pvp) title, values from dbc -}; + // REUSE + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23, // title_id known (pvp) title, values from dbc + ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT = 24, // game_event_id 0 -#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 24 // maximum value in AchievementCriteriaDataType enum + MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE +}; struct AchievementCriteriaData { @@ -97,11 +97,6 @@ struct AchievementCriteriaData { uint32 percent; } health; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD = 4 - struct - { - uint32 own_team_flag; - } player_dead; // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5 // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7 struct @@ -109,11 +104,6 @@ struct AchievementCriteriaData uint32 spell_id; uint32 effect_idx; } aura; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6 - struct - { - uint32 id; - } area; // ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8 struct { @@ -131,11 +121,6 @@ struct AchievementCriteriaData uint32 gender; } gender; // ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT = 11 (no data) - // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12 - struct - { - uint32 difficulty; - } difficulty; // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13 struct { @@ -174,17 +159,17 @@ struct AchievementCriteriaData { uint32 mapId; } map_id; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY = 21 - struct - { - uint32 nth_birthday; - } birthday_login; // ACHIEVEMENT_CRITERIA_DATA_TYPE_KNOWN_TITLE = 22 struct { uint32 title_id; } known_title; - // ... + // ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT = 24 + struct + { + uint32 id; + } game_event; + // raw struct { uint32 value1; @@ -248,6 +233,7 @@ typedef std::unordered_map<uint32, AchievementRewardLocale> AchievementRewardLoc struct CompletedAchievementData { time_t date; + std::set<uint64> guids; bool changed; }; @@ -261,45 +247,53 @@ enum ProgressType PROGRESS_HIGHEST }; +template<class T> class AchievementMgr { public: - AchievementMgr(Player* player); + AchievementMgr(T* owner); ~AchievementMgr(); void Reset(); static void DeleteFromDB(uint32 lowguid); void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult); void SaveToDB(SQLTransaction& trans); - void ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, bool evenIfCriteriaComplete = false); - void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, Unit* unit = NULL); - void CompletedAchievement(AchievementEntry const* entry); - void CheckAllAchievementCriteria(); - void SendAllAchievementData() const; - void SendRespondInspectAchievements(Player* player) const; + void ResetAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); + void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, Unit const* unit = NULL, Player* referencePlayer = NULL); + void CompletedAchievement(AchievementEntry const* entry, Player* referencePlayer); + void CheckAllAchievementCriteria(Player* referencePlayer); + void SendAllAchievementData(Player* receiver) const; + void SendAchievementInfo(Player* receiver, uint32 achievementId = 0) const; bool HasAchieved(uint32 achievementId) const; - Player* GetPlayer() const { return m_player; } + T* GetOwner() const { return _owner; } + void UpdateTimedAchievements(uint32 timeDiff); void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0); void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); // used for quest and scripted timed achievements + uint32 GetAchievementPoints() const { return _achievementPoints; } private: void SendAchievementEarned(AchievementEntry const* achievement) const; void SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const; CriteriaProgress* GetCriteriaProgress(AchievementCriteriaEntry const* entry); - void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype = PROGRESS_SET); + void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint64 changeValue, Player* referencePlayer, ProgressType ptype = PROGRESS_SET); void RemoveCriteriaProgress(AchievementCriteriaEntry const* entry); - void CompletedCriteriaFor(AchievementEntry const* achievement); + void CompletedCriteriaFor(AchievementEntry const* achievement, Player* referencePlayer); bool IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement); bool IsCompletedAchievement(AchievementEntry const* entry); - bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement); - void BuildAllDataPacket(WorldPacket* data) const; + bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer); + void SendPacket(WorldPacket* data) const; - Player* m_player; + bool ConditionsSatisfied(AchievementCriteriaEntry const* criteria, Player* referencePlayer) const; + bool RequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit const* unit, Player* referencePlayer) const; + bool AdditionalRequirementsSatisfied(AchievementCriteriaEntry const* criteria, uint64 miscValue1, uint64 miscValue2, Unit const* unit, Player* referencePlayer) const; + + T* _owner; CriteriaProgressMap m_criteriaProgress; CompletedAchievementMap m_completedAchievements; typedef std::map<uint32, uint32> TimedAchievementMap; TimedAchievementMap m_timedAchievements; // Criteria id/time left in MS + uint32 _achievementPoints; }; class AchievementGlobalMgr @@ -308,15 +302,18 @@ class AchievementGlobalMgr ~AchievementGlobalMgr() { } public: + static char const* GetCriteriaTypeString(AchievementCriteriaTypes type); + static char const* GetCriteriaTypeString(uint32 type); + static AchievementGlobalMgr* instance() { static AchievementGlobalMgr instance; return &instance; } - AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type) const + AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type, bool guild = false) const { - return m_AchievementCriteriasByType[type]; + return guild ? m_GuildAchievementCriteriasByType[type] : m_AchievementCriteriasByType[type]; } AchievementCriteriaEntryList const& GetTimedAchievementCriteriaByType(AchievementCriteriaTimedTypes type) const @@ -364,6 +361,24 @@ class AchievementGlobalMgr m_allCompletedAchievements.insert(achievement->ID); } + bool IsGroupCriteriaType(AchievementCriteriaTypes type) const + { + switch (type) + { + case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: + case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: // NYI + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: + case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: // NYI + case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND: // NYI + return true; + default: + break; + } + + return false; + } + void LoadAchievementCriteriaList(); void LoadAchievementCriteriaData(); void LoadAchievementReferenceList(); @@ -377,6 +392,7 @@ class AchievementGlobalMgr // store achievement criterias by type to speed up lookup AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; + AchievementCriteriaEntryList m_GuildAchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; AchievementCriteriaEntryList m_AchievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX]; diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index f4699f0519e..40935a0712c 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -231,7 +231,7 @@ void AuctionHouseMgr::SendAuctionOutbiddedMail(AuctionEntry* auction, uint32 new } //this function sends mail, when auction is cancelled to old bidder -void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans) +void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans, Item* item) { uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); Player* bidder = ObjectAccessor::FindPlayer(bidder_guid); @@ -240,6 +240,9 @@ void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQ if (!bidder) bidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(bidder_guid); + if (bidder) + bidder->GetSession()->SendAuctionRemovedNotification(auction->Id, auction->itemEntry, item->GetItemRandomPropertyId()); + // bidder exist if (bidder || bidder_accId) MailDraft(auction->BuildAuctionMailSubject(AUCTION_CANCELLED_TO_BIDDER), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, auction->deposit, 0)) @@ -574,7 +577,7 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player if (itemRandProp) { - char* const* temp = itemRandProp->nameSuffix; + char* temp = itemRandProp->nameSuffix; // dbc local name if (temp) @@ -614,7 +617,7 @@ bool AuctionEntry::BuildAuctionInfo(WorldPacket& data) const data << uint32(Id); data << uint32(item->GetEntry()); - for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i) + for (uint8 i = 0; i < PROP_ENCHANTMENT_SLOT_0; ++i) // PROP_ENCHANTMENT_SLOT_0 = 10 { data << uint32(item->GetEnchantmentId(EnchantmentSlot(i))); data << uint32(item->GetEnchantmentDuration(EnchantmentSlot(i))); @@ -627,13 +630,13 @@ bool AuctionEntry::BuildAuctionInfo(WorldPacket& data) const data << uint32(item->GetSpellCharges()); // item->charge FFFFFFF data << uint32(0); // Unknown data << uint64(owner); // Auction->owner - data << uint32(startbid); // Auction->startbid (not sure if useful) - data << uint32(bid ? GetAuctionOutBid() : 0); + data << uint64(startbid); // Auction->startbid (not sure if useful) + data << uint64(bid ? GetAuctionOutBid() : 0); // Minimal outbid - data << uint32(buyout); // Auction->buyout + data << uint64(buyout); // Auction->buyout data << uint32((expire_time - time(NULL)) * IN_MILLISECONDS); // time left data << uint64(bidder); // auction->bidder current - data << uint32(bid); // current bid + data << uint64(bid); // current bid return true; } diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h index 597da13cb1b..8e74b4c53a6 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.h +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h @@ -166,7 +166,7 @@ class AuctionHouseMgr void SendAuctionSuccessfulMail(AuctionEntry* auction, SQLTransaction& trans); void SendAuctionExpiredMail(AuctionEntry* auction, SQLTransaction& trans); void SendAuctionOutbiddedMail(AuctionEntry* auction, uint32 newPrice, Player* newBidder, SQLTransaction& trans); - void SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans); + void SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans, Item* item); static uint32 GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count); static AuctionHouseEntry const* GetAuctionHouseEntry(uint32 factionTemplateId); diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index b04d0d360ee..5ef3426d602 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -37,6 +37,7 @@ Battlefield::Battlefield() m_isActive = false; m_DefenderTeam = TEAM_NEUTRAL; + m_Guid = 0; m_TypeId = 0; m_BattleId = 0; m_ZoneId = 0; @@ -106,7 +107,7 @@ void Battlefield::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/) if (m_PlayersInWar[player->GetTeamId()].find(player->GetGUID()) != m_PlayersInWar[player->GetTeamId()].end()) { m_PlayersInWar[player->GetTeamId()].erase(player->GetGUID()); - player->GetSession()->SendBfLeaveMessage(m_BattleId); + player->GetSession()->SendBfLeaveMessage(m_Guid); if (Group* group = player->GetGroup()) // Remove the player from the raid group group->RemoveMember(player->GetGUID()); @@ -210,7 +211,7 @@ void Battlefield::InvitePlayerToQueue(Player* player) return; if (m_PlayersInQueue[player->GetTeamId()].size() <= m_MinPlayer || m_PlayersInQueue[GetOtherTeam(player->GetTeamId())].size() >= m_MinPlayer) - player->GetSession()->SendBfInvitePlayerToQueue(m_BattleId); + player->GetSession()->SendBfInvitePlayerToQueue(m_Guid); } void Battlefield::InvitePlayersInQueueToWar() @@ -279,7 +280,7 @@ void Battlefield::InvitePlayerToWar(Player* player) m_PlayersWillBeKick[player->GetTeamId()].erase(player->GetGUID()); m_InvitedPlayers[player->GetTeamId()][player->GetGUID()] = time(NULL) + m_TimeForAcceptInvite; - player->GetSession()->SendBfInvitePlayerToWar(m_BattleId, m_ZoneId, m_TimeForAcceptInvite); + player->GetSession()->SendBfInvitePlayerToWar(m_Guid, m_ZoneId, m_TimeForAcceptInvite); } void Battlefield::InitStalker(uint32 entry, Position const& pos) @@ -357,6 +358,7 @@ void Battlefield::DoPlaySoundToAll(uint32 SoundID) WorldPacket data; data.Initialize(SMSG_PLAY_SOUND, 4); data << uint32(SoundID); + data << uint64(0); for (int team = 0; team < BG_TEAMS_COUNT; team++) for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) @@ -375,7 +377,7 @@ void Battlefield::PlayerAcceptInviteToQueue(Player* player) // Add player in queue m_PlayersInQueue[player->GetTeamId()].insert(player->GetGUID()); // Send notification - player->GetSession()->SendBfQueueInviteResponse(m_BattleId, m_ZoneId); + player->GetSession()->SendBfQueueInviteResponse(m_Guid, m_ZoneId); } // Called in WorldSession::HandleBfExitRequest @@ -393,7 +395,7 @@ void Battlefield::PlayerAcceptInviteToWar(Player* player) if (AddOrSetPlayerToCorrectBfGroup(player)) { - player->GetSession()->SendBfEntered(m_BattleId); + player->GetSession()->SendBfEntered(m_Guid); m_PlayersInWar[player->GetTeamId()].insert(player->GetGUID()); m_InvitedPlayers[player->GetTeamId()].erase(player->GetGUID()); @@ -476,14 +478,12 @@ void Battlefield::HideNpc(Creature* creature) creature->CombatStop(); creature->SetReactState(REACT_PASSIVE); creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - creature->SetPhaseMask(2, true); creature->DisappearAndDie(); creature->SetVisible(false); } void Battlefield::ShowNpc(Creature* creature, bool aggressive) { - creature->SetPhaseMask(1, true); creature->SetVisible(true); creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); if (!creature->IsAlive()) @@ -796,7 +796,6 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl delete creature; return nullptr; } - creature->SetHomePosition(x, y, z, o); CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry); diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 15498d1f045..0aa6a51d6bf 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -23,7 +23,8 @@ enum BattlefieldTypes { - BATTLEFIELD_WG // Wintergrasp + BATTLEFIELD_WG, // Wintergrasp + BATTLEFIELD_TB // Tol Barad (cataclysm) }; enum BattlefieldIDs @@ -222,6 +223,7 @@ class Battlefield : public ZoneScript uint32 GetTypeId() { return m_TypeId; } uint32 GetZoneId() { return m_ZoneId; } + uint64 GetGUID() { return m_Guid; } void TeamApplyBuff(TeamId team, uint32 spellId, uint32 spellId2 = 0); @@ -342,6 +344,8 @@ class Battlefield : public ZoneScript void InitStalker(uint32 entry, Position const& pos); protected: + uint64 m_Guid; + uint64 StalkerGuid; uint32 m_Timer; // Global timer for event bool m_IsEnabled; diff --git a/src/server/game/Battlefield/BattlefieldMgr.cpp b/src/server/game/Battlefield/BattlefieldMgr.cpp index 8aa58f0ac4b..c531e22bc20 100644 --- a/src/server/game/Battlefield/BattlefieldMgr.cpp +++ b/src/server/game/Battlefield/BattlefieldMgr.cpp @@ -123,6 +123,15 @@ Battlefield* BattlefieldMgr::GetBattlefieldByBattleId(uint32 battleId) return NULL; } +Battlefield* BattlefieldMgr::GetBattlefieldByGUID(uint64 guid) +{ + for (BattlefieldSet::iterator itr = _battlefieldSet.begin(); itr != _battlefieldSet.end(); ++itr) + if ((*itr)->GetGUID() == guid) + return *itr; + + return NULL; +} + ZoneScript* BattlefieldMgr::GetZoneScript(uint32 zoneId) { BattlefieldMap::iterator itr = _battlefieldMap.find(zoneId); diff --git a/src/server/game/Battlefield/BattlefieldMgr.h b/src/server/game/Battlefield/BattlefieldMgr.h index f51a7177a88..0fa4add13a8 100644 --- a/src/server/game/Battlefield/BattlefieldMgr.h +++ b/src/server/game/Battlefield/BattlefieldMgr.h @@ -44,6 +44,7 @@ class BattlefieldMgr // return assigned battlefield Battlefield* GetBattlefieldToZoneId(uint32 zoneId); Battlefield* GetBattlefieldByBattleId(uint32 battleId); + Battlefield* GetBattlefieldByGUID(uint64 guid); ZoneScript* GetZoneScript(uint32 zoneId); diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index 0ba9e816b2e..03c2992e812 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -73,7 +73,7 @@ enum WintergraspSpells // Other spells SPELL_WINTERGRASP_WATER = 36444, SPELL_ESSENCE_OF_WINTERGRASP = 58045, - SPELL_WINTERGRASP_RESTRICTED_FLIGHT_AREA = 58730, + SPELL_WINTERGRASP_RESTRICTED_FLIGHT_AREA = 91604, // Phasing spells SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT = 56618, // ADDS PHASE 16 diff --git a/src/server/game/Battlegrounds/Arena.cpp b/src/server/game/Battlegrounds/Arena.cpp index cdc6fc3cac0..7a72afa2b12 100644 --- a/src/server/game/Battlegrounds/Arena.cpp +++ b/src/server/game/Battlegrounds/Arena.cpp @@ -18,6 +18,8 @@ #include "Arena.h" #include "ArenaScore.h" #include "ArenaTeamMgr.h" +#include "GuildMgr.h" +#include "Guild.h" #include "Language.h" #include "ObjectAccessor.h" #include "Player.h" @@ -141,6 +143,7 @@ void Arena::EndBattleground(uint32 winner) uint32 winnerMatchmakerRating = 0; int32 winnerChange = 0; int32 winnerMatchmakerChange = 0; + bool guildAwarded = false; ArenaTeam* winnerArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(winner)); ArenaTeam* loserArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(winner))); @@ -221,11 +224,20 @@ void Arena::EndBattleground(uint32 winner) uint32 rating = player->GetArenaPersonalRating(winnerArenaTeam->GetSlot()); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, rating ? rating : 1); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA, GetMapId()); + player->ModifyCurrency(CURRENCY_TYPE_CONQUEST_META_ARENA, sWorld->getIntConfig(CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD)); // Last standing - Rated 5v5 arena & be solely alive player if (GetArenaType() == ARENA_TYPE_5v5 && aliveWinners == 1 && player->IsAlive()) player->CastSpell(player, SPELL_LAST_MAN_STANDING, true); + if (!guildAwarded) + { + guildAwarded = true; + if (uint32 guildId = GetBgMap()->GetOwnerGuildId(player->GetBGTeam())) + if (Guild* guild = sGuildMgr->GetGuildById(guildId)) + guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, std::max<uint32>(winnerArenaTeam->GetRating(), 1), 0, 0, NULL, player); + } + winnerArenaTeam->MemberWon(player, loserMatchmakerRating, winnerMatchmakerChange); } else diff --git a/src/server/game/Battlegrounds/ArenaScore.h b/src/server/game/Battlegrounds/ArenaScore.h index 638275b1833..162cf729181 100644 --- a/src/server/game/Battlegrounds/ArenaScore.h +++ b/src/server/game/Battlegrounds/ArenaScore.h @@ -20,29 +20,76 @@ #include "BattlegroundScore.h" #include "SharedDefines.h" +#include "Player.h" +#include "ObjectAccessor.h" struct ArenaScore : public BattlegroundScore { friend class Arena; protected: - ArenaScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid), TeamId(team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE) { } + ArenaScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), TeamId(team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE) { } - void AppendToPacket(WorldPacket& data) final + void AppendToPacket(WorldPacket& data, ByteBuffer& content) final { - data << uint64(PlayerGuid); + uint32 primaryTree = 0; + if (Player* player = ObjectAccessor::FindPlayer(PlayerGuid)) + primaryTree = player->GetPrimaryTalentTree(player->GetActiveSpec()); - data << uint32(KillingBlows); - data << uint8(TeamId); - data << uint32(DamageDone); - data << uint32(HealingDone); + data.WriteBit(0); // Unk 1 + data.WriteBit(0); // Unk 2 + data.WriteBit(PlayerGuid[2]); + data.WriteBit(/*!IsArena*/ 0); // IsArena + data.WriteBit(0); // Unk 4 + data.WriteBit(0); // Unk 5 + data.WriteBit(0); // Unk 6 + data.WriteBit(PlayerGuid[3]); + data.WriteBit(PlayerGuid[0]); + data.WriteBit(PlayerGuid[5]); + data.WriteBit(PlayerGuid[1]); + data.WriteBit(PlayerGuid[6]); + data.WriteBit(TeamId); + data.WriteBit(PlayerGuid[7]); - BuildObjectivesBlock(data); + content << uint32(HealingDone); // healing done + content << uint32(DamageDone); // damage done + + content.WriteByteSeq(PlayerGuid[4]); + content << uint32(KillingBlows); + + //if (unk5) + // content << int32(RatingChange); // RatingChange + + content.WriteByteSeq(PlayerGuid[5]); + + //if (unk 6) + // content << uint32(); + + //if (unk 2) + // content << uint32(); + + content.WriteByteSeq(PlayerGuid[1]); + content.WriteByteSeq(PlayerGuid[6]); + + content << int32(primaryTree); + + BuildObjectivesBlock(data, content); + + data.WriteBit(PlayerGuid[4]); + + content.WriteByteSeq(PlayerGuid[0]); + content.WriteByteSeq(PlayerGuid[3]); + + //if (unk 4) + // content << uint32() unk + + content.WriteByteSeq(PlayerGuid[7]); + content.WriteByteSeq(PlayerGuid[2]); } - void BuildObjectivesBlock(WorldPacket& data) final + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& /*content*/) final { - data << uint32(0); // Objectives Count + data.WriteBits(0, 24); // Objectives Count } // For Logging purpose @@ -86,14 +133,19 @@ struct ArenaTeamScore uint32 ratingWon = std::max(RatingChange, 0); // should be old rating, new rating, and client will calculate rating change itself + data << uint32(MatchmakerRating); data << uint32(ratingLost); data << uint32(ratingWon); - data << uint32(MatchmakerRating); + } + + void BuildTeamInfoLengthBlock(WorldPacket& data) + { + data.WriteBits(TeamName.length(), 8); } void BuildTeamInfoBlock(WorldPacket& data) { - data << TeamName; + data.WriteString(TeamName); } int32 RatingChange; diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index 2ca60534f30..17d95dbbe6b 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -41,14 +41,16 @@ ArenaTeam::ArenaTeam() ArenaTeam::~ArenaTeam() { } -bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string const& teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor) +bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string const& arenaTeamName, + uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, + uint8 borderStyle, uint32 borderColor) { // Check if captain is present if (!ObjectAccessor::FindPlayer(captainGuid)) return false; // Check if arena team name is already taken - if (sArenaTeamMgr->GetArenaTeamByName(teamName)) + if (sArenaTeamMgr->GetArenaTeamByName(arenaTeamName)) return false; // Generate new arena team id @@ -57,7 +59,7 @@ bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string const& teamNa // Assign member variables CaptainGuid = captainGuid; Type = type; - TeamName = teamName; + TeamName = arenaTeamName; BackgroundColor = backgroundColor; EmblemStyle = emblemStyle; EmblemColor = emblemColor; @@ -179,7 +181,7 @@ bool ArenaTeam::AddMember(uint64 playerGuid) player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 1); } - TC_LOG_INFO("bg.arena", "Player: %s [GUID: %u] joined arena team type: %u [Id: %u, Name: %s].", playerName.c_str(), GUID_LOPART(playerGuid), GetType(), GetId(), GetName().c_str()); + TC_LOG_DEBUG("bg.arena", "Player: %s [GUID: %u] joined arena team type: %u [Id: %u, Name: %s].", playerName.c_str(), GUID_LOPART(playerGuid), GetType(), GetId(), GetName().c_str()); return true; } @@ -321,10 +323,9 @@ void ArenaTeam::DelMember(uint64 guid, bool cleanDb) break; } - // Inform player and remove arena team info from player data + // Remove arena team info from player data if (Player* player = ObjectAccessor::FindPlayer(guid)) { - player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0); // delete all info regarding this team for (uint32 i = 0; i < ARENA_TEAM_END; ++i) player->SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType(i), 0); @@ -343,19 +344,18 @@ void ArenaTeam::DelMember(uint64 guid, bool cleanDb) void ArenaTeam::Disband(WorldSession* session) { - // Remove all members from arena team - while (!Members.empty()) - DelMember(Members.front().Guid, false); - // Broadcast update if (session) { BroadcastEvent(ERR_ARENA_TEAM_DISBANDED_S, 0, 2, session->GetPlayerName(), GetName(), ""); - if (Player* player = session->GetPlayer()) TC_LOG_DEBUG("bg.arena", "Player: %s [GUID: %u] disbanded arena team type: %u [Id: %u, Name: %s].", player->GetName().c_str(), player->GetGUIDLow(), GetType(), GetId(), GetName().c_str()); } + // Remove all members from arena team + while (!Members.empty()) + DelMember(Members.front().Guid, false); + // Update database SQLTransaction trans = CharacterDatabase.BeginTransaction(); @@ -580,6 +580,20 @@ uint8 ArenaTeam::GetSlotByType(uint32 type) return 0xFF; } +uint8 ArenaTeam::GetTypeBySlot(uint8 slot) +{ + switch (slot) + { + case 0: return ARENA_TEAM_2v2; + case 1: return ARENA_TEAM_3v3; + case 2: return ARENA_TEAM_5v5; + default: + break; + } + TC_LOG_ERROR("bg.arena", "FATAL: Unknown arena team slot %u for some arena team", slot); + return 0xFF; +} + bool ArenaTeam::IsMember(uint64 guid) const { for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr) @@ -589,32 +603,6 @@ bool ArenaTeam::IsMember(uint64 guid) const return false; } -uint32 ArenaTeam::GetPoints(uint32 memberRating) -{ - // Returns how many points would be awarded with this team type with this rating - float points; - - uint32 rating = memberRating + 150 < Stats.Rating ? memberRating : Stats.Rating; - - if (rating <= 1500) - { - if (sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) < 6) - points = (float)rating * 0.22f + 14.0f; - else - points = 344; - } - else - points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating)); - - // Type penalties for teams < 5v5 - if (Type == ARENA_TEAM_2v2) - points *= 0.76f; - else if (Type == ARENA_TEAM_3v3) - points *= 0.88f; - - return (uint32) points; -} - uint32 ArenaTeam::GetAverageMMR(Group* group) const { if (!group) @@ -628,7 +616,7 @@ uint32 ArenaTeam::GetAverageMMR(Group* group) const if (!ObjectAccessor::FindPlayer(itr->Guid)) continue; - // Skip if player is not member of group + // Skip if player is not a member of group if (!group->IsMember(itr->Guid)) continue; @@ -652,7 +640,7 @@ float ArenaTeam::GetChanceAgainst(uint32 ownRating, uint32 opponentRating) return 1.0f / (1.0f + exp(log(10.0f) * (float)((float)opponentRating - (float)ownRating) / 650.0f)); } -int32 ArenaTeam::GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won /*, float& confidence_factor*/) +int32 ArenaTeam::GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won) { // 'Chance' calculation - to beat the opponent // This is a simulation. Not much info on how it really works @@ -731,17 +719,17 @@ void ArenaTeam::FinishGame(int32 mod) } } -int32 ArenaTeam::WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change) +int32 ArenaTeam::WonAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& ratingChange) { // Called when the team has won // Change in Matchmaker rating - int32 mod = GetMatchmakerRatingMod(Own_MMRating, Opponent_MMRating, true); + int32 mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, true); // Change in Team Rating - rating_change = GetRatingMod(Stats.Rating, Opponent_MMRating, true); + ratingChange = GetRatingMod(Stats.Rating, opponentMMRating, true); // Modify the team stats accordingly - FinishGame(rating_change); + FinishGame(ratingChange); // Update number of wins per season and week Stats.WeekWins += 1; @@ -751,23 +739,23 @@ int32 ArenaTeam::WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32 return mod; } -int32 ArenaTeam::LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change) +int32 ArenaTeam::LostAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& ratingChange) { // Called when the team has lost // Change in Matchmaker Rating - int32 mod = GetMatchmakerRatingMod(Own_MMRating, Opponent_MMRating, false); + int32 mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, false); // Change in Team Rating - rating_change = GetRatingMod(Stats.Rating, Opponent_MMRating, false); + ratingChange = GetRatingMod(Stats.Rating, opponentMMRating, false); // Modify the team stats accordingly - FinishGame(rating_change); + FinishGame(ratingChange); // return the rating change, used to display it on the results screen return mod; } -void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange) +void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange) { // Called for each participant of a match after losing for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr) @@ -779,7 +767,7 @@ void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32 itr->ModifyPersonalRating(player, mod, GetType()); // Update matchmaker rating - itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot()); + itr->ModifyMatchmakerRating(matchmakerRatingChange, GetSlot()); // Update personal played stats itr->WeekGames +=1; @@ -793,7 +781,7 @@ void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32 } } -void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange) +void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 matchmakerRatingChange) { // Called for offline player after ending rated arena match! for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr) @@ -805,7 +793,7 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, i itr->ModifyPersonalRating(NULL, mod, GetType()); // update matchmaker rating - itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot()); + itr->ModifyMatchmakerRating(matchmakerRatingChange, GetSlot()); // update personal played stats itr->WeekGames += 1; @@ -815,7 +803,7 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, i } } -void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange) +void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange) { // called for each participant after winning a match for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr) @@ -827,7 +815,7 @@ void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 itr->ModifyPersonalRating(player, mod, GetType()); // update matchmaker rating - itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot()); + itr->ModifyMatchmakerRating(matchmakerRatingChange, GetSlot()); // update personal stats itr->WeekGames +=1; @@ -842,36 +830,6 @@ void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 } } -void ArenaTeam::UpdateArenaPointsHelper(std::map<uint32, uint32>& playerPoints) -{ - // Called after a match has ended and the stats are already modified - // Helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons) - // 10 played games per week is a minimum - if (Stats.WeekGames < 10) - return; - - // To get points, a player has to participate in at least 30% of the matches - uint32 requiredGames = (uint32)ceil(Stats.WeekGames * 0.3f); - - for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr) - { - // The player participated in enough games, update his points - uint32 pointsToAdd = 0; - if (itr->WeekGames >= requiredGames) - pointsToAdd = GetPoints(itr->PersonalRating); - - std::map<uint32, uint32>::iterator plr_itr = playerPoints.find(GUID_LOPART(itr->Guid)); - if (plr_itr != playerPoints.end()) - { - // Check if there is already more points - if (plr_itr->second < pointsToAdd) - playerPoints[GUID_LOPART(itr->Guid)] = pointsToAdd; - } - else - playerPoints[GUID_LOPART(itr->Guid)] = pointsToAdd; - } -} - void ArenaTeam::SaveToDB() { // Save team and member stats to db diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h index d3b6342b273..c4f6201434f 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.h +++ b/src/server/game/Battlegrounds/ArenaTeam.h @@ -19,8 +19,10 @@ #ifndef TRINITYCORE_ARENATEAM_H #define TRINITYCORE_ARENATEAM_H +#include "Define.h" #include "QueryResult.h" #include <list> +#include <string> #include <map> class WorldSession; @@ -38,6 +40,7 @@ enum ArenaTeamCommandTypes enum ArenaTeamCommandErrors { + ERR_ARENA_TEAM_CREATED = 0x00, ERR_ARENA_TEAM_INTERNAL = 0x01, ERR_ALREADY_IN_ARENA_TEAM = 0x02, ERR_ALREADY_IN_ARENA_TEAM_S = 0x03, @@ -56,7 +59,8 @@ enum ArenaTeamCommandErrors ERR_ARENA_TEAM_TARGET_TOO_HIGH_S = 0x16, ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S = 0x17, ERR_ARENA_TEAM_NOT_FOUND = 0x1B, - ERR_ARENA_TEAMS_LOCKED = 0x1E + ERR_ARENA_TEAMS_LOCKED = 0x1E, + ERR_ARENA_TEAM_TOO_MANY_CREATE = 0x21, }; enum ArenaTeamEvents @@ -69,14 +73,6 @@ enum ArenaTeamEvents ERR_ARENA_TEAM_DISBANDED_S = 8 // captain name + arena team name }; -/* -need info how to send these ones: -ERR_ARENA_TEAM_YOU_JOIN_S - client show it automatically when accept invite -ERR_ARENA_TEAM_TARGET_TOO_LOW_S -ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S -ERR_ARENA_TEAM_LEVEL_TOO_LOW_I -*/ - enum ArenaTeamTypes { ARENA_TEAM_2v2 = 2, @@ -118,17 +114,20 @@ class ArenaTeam ArenaTeam(); ~ArenaTeam(); - bool Create(uint64 captainGuid, uint8 type, std::string const& teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor); + bool Create(uint64 captainGuid, uint8 type, std::string const& teamName, + uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, + uint8 borderStyle, uint32 borderColor); void Disband(WorldSession* session); void Disband(); typedef std::list<ArenaTeamMember> MemberList; - uint32 GetId() const { return TeamId; } - uint32 GetType() const { return Type; } - uint8 GetSlot() const { return GetSlotByType(GetType()); } + uint32 GetId() const { return TeamId; } + uint32 GetType() const { return Type; } + uint8 GetSlot() const { return GetSlotByType(GetType()); } static uint8 GetSlotByType(uint32 type); - uint64 GetCaptain() const { return CaptainGuid; } + static uint8 GetTypeBySlot(uint8 slot); + uint64 GetCaptain() const { return CaptainGuid; } std::string const& GetName() const { return TeamName; } const ArenaTeamStats& GetStats() const { return Stats; } @@ -138,9 +137,6 @@ class ArenaTeam void SetCaptain(uint64 guid); bool SetName(std::string const& name); bool AddMember(uint64 PlayerGuid); - - // Shouldn't be uint64 ed, because than can reference guid from members on Disband - // and this method removes given record from list. So invalid reference can happen. void DelMember(uint64 guid, bool cleanDb); size_t GetMembersSize() const { return Members.size(); } @@ -170,27 +166,26 @@ class ArenaTeam void SendStats(WorldSession* session); void Inspect(WorldSession* session, uint64 guid); - uint32 GetPoints(uint32 MemberRating); - int32 GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won); - int32 GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won); - float GetChanceAgainst(uint32 ownRating, uint32 opponentRating); - int32 WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change); - void MemberWon(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange); - int32 LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change); - void MemberLost(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange = -12); - void OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange = -12); + static int32 GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won); + static int32 GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won); + static float GetChanceAgainst(uint32 ownRating, uint32 opponentRating); + + int32 WonAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& rating_change); + void MemberWon(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange = 12); - void UpdateArenaPointsHelper(std::map<uint32, uint32> & PlayerPoints); + int32 LostAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& rating_change); + void MemberLost(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange = -12); + void OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 matchmakerRatingChange = -12); void FinishWeek(); void FinishGame(int32 mod); protected: - uint32 TeamId; - uint8 Type; + uint32 TeamId; + uint8 Type; std::string TeamName; - uint64 CaptainGuid; + uint64 CaptainGuid; uint32 BackgroundColor; // ARGB format uint8 EmblemStyle; // icon id @@ -198,7 +193,7 @@ class ArenaTeam uint8 BorderStyle; // border image id uint32 BorderColor; // ARGB format - MemberList Members; + MemberList Members; ArenaTeamStats Stats; }; #endif diff --git a/src/server/game/Battlegrounds/ArenaTeamMgr.cpp b/src/server/game/Battlegrounds/ArenaTeamMgr.cpp index cd49158b5d0..0098c8a1bcb 100644 --- a/src/server/game/Battlegrounds/ArenaTeamMgr.cpp +++ b/src/server/game/Battlegrounds/ArenaTeamMgr.cpp @@ -134,59 +134,3 @@ void ArenaTeamMgr::LoadArenaTeams() TC_LOG_INFO("server.loading", ">> Loaded %u arena teams in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } - -void ArenaTeamMgr::DistributeArenaPoints() -{ - // Used to distribute arena points based on last week's stats - sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_START); - - sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START); - - // Temporary structure for storing maximum points to add values for all players - std::map<uint32, uint32> PlayerPoints; - - // At first update all points for all team members - for (ArenaTeamContainer::iterator teamItr = GetArenaTeamMapBegin(); teamItr != GetArenaTeamMapEnd(); ++teamItr) - if (ArenaTeam* at = teamItr->second) - at->UpdateArenaPointsHelper(PlayerPoints); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - - PreparedStatement* stmt; - - // Cycle that gives points to all players - for (std::map<uint32, uint32>::iterator playerItr = PlayerPoints.begin(); playerItr != PlayerPoints.end(); ++playerItr) - { - // Add points to player if online - if (Player* player = HashMapHolder<Player>::Find(playerItr->first)) - player->ModifyArenaPoints(playerItr->second, trans); - else // Update database - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_CHAR_ARENA_POINTS); - stmt->setUInt32(0, playerItr->second); - stmt->setUInt32(1, playerItr->first); - trans->Append(stmt); - } - } - - CharacterDatabase.CommitTransaction(trans); - - PlayerPoints.clear(); - - sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END); - - sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START); - for (ArenaTeamContainer::iterator titr = GetArenaTeamMapBegin(); titr != GetArenaTeamMapEnd(); ++titr) - { - if (ArenaTeam* at = titr->second) - { - at->FinishWeek(); - at->SaveToDB(); - at->NotifyStatsChanged(); - } - } - - sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END); - - sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_END); -} diff --git a/src/server/game/Battlegrounds/ArenaTeamMgr.h b/src/server/game/Battlegrounds/ArenaTeamMgr.h index 118e9674fbf..eaf39278c28 100644 --- a/src/server/game/Battlegrounds/ArenaTeamMgr.h +++ b/src/server/game/Battlegrounds/ArenaTeamMgr.h @@ -46,8 +46,6 @@ public: ArenaTeamContainer::iterator GetArenaTeamMapBegin() { return ArenaTeamStore.begin(); } ArenaTeamContainer::iterator GetArenaTeamMapEnd() { return ArenaTeamStore.end(); } - void DistributeArenaPoints(); - uint32 GenerateArenaTeamId(); void SetNextArenaTeamId(uint32 Id) { NextArenaTeamId = Id; } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 86236cd0f2b..584117e7666 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -26,6 +26,8 @@ #include "Formulas.h" #include "GridNotifiersImpl.h" #include "Group.h" +#include "GuildMgr.h" +#include "Guild.h" #include "MapManager.h" #include "Object.h" #include "ObjectMgr.h" @@ -112,6 +114,7 @@ void Battleground::BroadcastWorker(Do& _do) Battleground::Battleground() { + m_Guid = 0; m_TypeID = BATTLEGROUND_TYPE_NONE; m_RandomTypeID = BATTLEGROUND_TYPE_NONE; m_InstanceID = 0; @@ -126,6 +129,7 @@ Battleground::Battleground() m_IsArena = false; _winnerTeamId = BG_TEAM_NEUTRAL; m_StartTime = 0; + m_CountdownTimer = 0; m_ResetStatTimer = 0; m_ValidStartPositionTimer = 0; m_Events = 0; @@ -244,7 +248,7 @@ void Battleground::Update(uint32 diff) // after 47 minutes without one team losing, the arena closes with no winner and no rating change if (isArena()) { - if (GetStartTime() >= 47 * MINUTE*IN_MILLISECONDS) + if (GetElapsedTime() >= 47 * MINUTE*IN_MILLISECONDS) { EndBattleground(0); return; @@ -267,8 +271,12 @@ void Battleground::Update(uint32 diff) } // Update start time and reset stats timer - m_StartTime += diff; - m_ResetStatTimer += diff; + SetElapsedTime(GetElapsedTime() + diff); + if (GetStatus() == STATUS_WAIT_JOIN) + { + m_ResetStatTimer += diff; + m_CountdownTimer += diff; + } PostUpdateImpl(diff); } @@ -429,6 +437,9 @@ inline void Battleground::_ProcessJoin(uint32 diff) // ********************************************************* ModifyStartDelayTime(diff); + if (!isArena()) + SetRemainingTime(300000); + if (m_ResetStatTimer > 5000) { m_ResetStatTimer = 0; @@ -437,6 +448,23 @@ inline void Battleground::_ProcessJoin(uint32 diff) player->ResetAllPowers(); } + // Send packet every 10 seconds until the 2nd field reach 0 + if (m_CountdownTimer >= 10000) + { + uint32 countdownMaxForBGType = isArena() ? ARENA_COUNTDOWN_MAX : BATTLEGROUND_COUNTDOWN_MAX; + + WorldPacket data(SMSG_START_TIMER, 4+4+4); + data << uint32(0); // unk + data << uint32(countdownMaxForBGType - (GetElapsedTime() / 1000)); + data << uint32(countdownMaxForBGType); + + for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) + if (Player* player = ObjectAccessor::FindPlayer(itr->first)) + player->GetSession()->SendPacket(&data); + + m_CountdownTimer = 0; + } + if (!(m_Events & BG_STARTING_EVENT_1)) { m_Events |= BG_STARTING_EVENT_1; @@ -494,8 +522,12 @@ inline void Battleground::_ProcessJoin(uint32 diff) WorldPacket status; BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(m_TypeID, GetArenaType()); uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType(), player->GetBGTeam()); - player->SendDirectMessage(&status); + + sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, player, queueSlot, STATUS_IN_PROGRESS, player->GetBattlegroundQueueJoinTime(m_TypeID), GetElapsedTime(), GetArenaType()); + player->GetSession()->SendPacket(&status); + + // Correctly display EnemyUnitFrame + player->SetByteValue(PLAYER_BYTES_3, 3, player->GetBGTeam()); player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); player->ResetAllPowers(); @@ -536,6 +568,9 @@ inline void Battleground::_ProcessJoin(uint32 diff) sWorld->SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName().c_str(), GetMinLevel(), GetMaxLevel()); } } + + if (GetRemainingTime() > 0 && (m_EndTime -= diff) > 0) + SetRemainingTime(GetRemainingTime() - diff); } inline void Battleground::_ProcessLeave(uint32 diff) @@ -544,10 +579,10 @@ inline void Battleground::_ProcessLeave(uint32 diff) // *** BATTLEGROUND ENDING SYSTEM *** // ********************************************************* // remove all players from battleground after 2 minutes - m_EndTime -= diff; - if (m_EndTime <= 0) + SetRemainingTime(GetRemainingTime() - diff); + if (GetRemainingTime() <= 0) { - m_EndTime = 0; + SetRemainingTime(0); BattlegroundPlayerMap::iterator itr, next; for (itr = m_Players.begin(); itr != m_Players.end(); itr = next) { @@ -711,6 +746,7 @@ void Battleground::EndBattleground(uint32 winner) RemoveFromBGFreeSlotQueue(); int32 winmsg_id = 0; + bool guildAwarded = false; if (winner == ALLIANCE) { @@ -735,7 +771,7 @@ void Battleground::EndBattleground(uint32 winner) SetStatus(STATUS_WAIT_LEAVE); //we must set it this way, because end time is sent in packet! - m_EndTime = TIME_TO_AUTOREMOVE; + SetRemainingTime(TIME_AUTOCLOSE_BATTLEGROUND); WorldPacket pvpLogData; BuildPvPLogDataPacket(pvpLogData); @@ -766,28 +802,44 @@ void Battleground::EndBattleground(uint32 winner) player->getHostileRefManager().deleteReferences(); } - uint32 winner_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST); - uint32 loser_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST); - uint32 winner_arena = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_FIRST); + // remove temporary currency bonus auras before rewarding player + player->RemoveAura(SPELL_HONORABLE_DEFENDER_25Y); + player->RemoveAura(SPELL_HONORABLE_DEFENDER_60Y); + + uint32 winnerKills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST); + uint32 loserKills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST); // Reward winner team if (team == winner) { if (IsRandom() || BattlegroundMgr::IsBGWeekend(GetTypeID())) { - UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(winner_kills)); - if (CanAwardArenaPoints()) - player->ModifyArenaPoints(winner_arena); + UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(winnerKills)); if (!player->GetRandomWinner()) + { + // 100cp awarded for the first random battleground won each day + player->ModifyCurrency(CURRENCY_TYPE_CONQUEST_META_ARENA, sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_CONQUEST_FIRST)); player->SetRandomWinner(true); + } } + else // 50cp awarded for each non-rated battleground won + player->ModifyCurrency(CURRENCY_TYPE_CONQUEST_META_ARENA, sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_CONQUEST_LAST)); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, 1); + if (!guildAwarded) + { + guildAwarded = true; + if (uint32 guildId = GetBgMap()->GetOwnerGuildId(player->GetBGTeam())) + { + if (Guild* guild = sGuildMgr->GetGuildById(guildId)) + guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, 1, 0, 0, NULL, player); + } + } } else { if (IsRandom() || BattlegroundMgr::IsBGWeekend(GetTypeID())) - UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(loser_kills)); + UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(loserKills)); } player->ResetAllPowers(); @@ -798,8 +850,9 @@ void Battleground::EndBattleground(uint32 winner) player->SendDirectMessage(&pvpLogData); WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType(), player->GetBGTeam()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, player->GetBattlegroundQueueJoinTime(GetTypeID()), GetElapsedTime(), GetArenaType()); player->SendDirectMessage(&data); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1); } @@ -861,10 +914,11 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac RemovePlayer(player, guid, team); // BG subclass specific code + BattlegroundTypeId bgTypeId = GetTypeID(); + BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType()); + if (participant) // if the player was a match participant, remove auras, calc rating, update queue { - BattlegroundTypeId bgTypeId = GetTypeID(); - BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType()); if (player) { player->ClearAfkReports(); @@ -882,7 +936,7 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac if (SendPacket) { WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_NONE, player->GetBattlegroundQueueJoinTime(bgTypeId), 0, 0); player->SendDirectMessage(&data); } @@ -916,6 +970,7 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG. // reset destination bg team player->SetBGTeam(0); + player->RemoveBattlegroundQueueJoinTime(bgTypeId); if (Transport) player->TeleportToBGEntryPoint(); @@ -931,8 +986,8 @@ void Battleground::Reset() { SetWinner(BG_TEAM_NEUTRAL); SetStatus(STATUS_WAIT_QUEUE); - SetStartTime(0); - SetEndTime(0); + SetElapsedTime(0); + SetRemainingTime(0); SetLastResurrectTime(0); m_Events = 0; @@ -958,7 +1013,7 @@ void Battleground::Reset() void Battleground::StartBattleground() { - SetStartTime(0); + SetElapsedTime(0); SetLastResurrectTime(0); // add BG to free slot queue AddToBGFreeSlotQueue(); @@ -982,10 +1037,12 @@ void Battleground::AddPlayer(Player* player) uint64 guid = player->GetGUID(); uint32 team = player->GetBGTeam(); + int32 primaryTree = player->GetPrimaryTalentTree(player->GetActiveSpec()); BattlegroundPlayer bp; bp.OfflineRemoveTime = 0; bp.Team = team; + bp.PrimaryTree = primaryTree; // Add to list/maps m_Players[guid] = bp; @@ -993,9 +1050,16 @@ void Battleground::AddPlayer(Player* player) UpdatePlayersCountByTeam(team, false); // +1 player WorldPacket data; - sBattlegroundMgr->BuildPlayerJoinedBattlegroundPacket(&data, player); + sBattlegroundMgr->BuildPlayerJoinedBattlegroundPacket(&data, player->GetGUID()); SendPacketToTeam(team, &data, player, false); + // BG Status packet + BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(m_TypeID, GetArenaType()); + uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId); + + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player, queueSlot, STATUS_IN_PROGRESS, player->GetBattlegroundQueueJoinTime(m_TypeID), GetElapsedTime(), GetArenaType()); + player->GetSession()->SendPacket(&data); + player->RemoveAurasByType(SPELL_AURA_MOUNTED); // add arena specific auras @@ -1014,7 +1078,16 @@ void Battleground::AddPlayer(Player* player) else { if (GetStatus() == STATUS_WAIT_JOIN) // not started yet + { player->CastSpell(player, SPELL_PREPARATION, true); // reduces all mana cost of spells. + + int32 countdownMaxForBGType = isArena() ? ARENA_COUNTDOWN_MAX : BATTLEGROUND_COUNTDOWN_MAX; + WorldPacket data(SMSG_START_TIMER, 4+4+4); + data << uint32(0); // unk + data << uint32(countdownMaxForBGType - (GetElapsedTime() / 1000)); + data << uint32(countdownMaxForBGType); + player->GetSession()->SendPacket(&data); + } } player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true); @@ -1190,31 +1263,51 @@ bool Battleground::HasFreeSlots() const void Battleground::BuildPvPLogDataPacket(WorldPacket& data) { - uint8 type = (isArena() ? 1 : 0); + ByteBuffer buff; + + data.Initialize(SMSG_PVP_LOG_DATA, (1 + 1 + 4 + 40 * GetPlayerScoresSize())); - data.Initialize(MSG_PVP_LOG_DATA, 1 + 1 + 4 + 40 * GetPlayerScoresSize()); - data << uint8(type); // type (battleground = 0 / arena = 1) + data.WriteBit(isRated()); + data.WriteBit(isArena()); - if (type) // arena + if (isArena()) { + // it seems this must be according to BG_WINNER_A/H and _NOT_ TEAM_A/H + for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) + _arenaTeamScores[i].BuildTeamInfoLengthBlock(data); + } + + size_t countPos = data.bitwpos(); + data.WriteBits(0, 21); + for (auto const& score : PlayerScores) + score.second->AppendToPacket(data, buff); + + data.PutBits(countPos, GetPlayerScoresSize(), 21); + data.WriteBit(GetStatus() == STATUS_WAIT_LEAVE); // If Ended + + if (isRated()) + { + // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) _arenaTeamScores[i].BuildRatingInfoBlock(data); + } + data.FlushBits(); + data.append(buff); + + if (isArena()) + { + // it seems this must be according to BG_WINNER_A/H and _NOT_ TEAM_A/H for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) _arenaTeamScores[i].BuildTeamInfoBlock(data); } + data << uint8(GetPlayersCountByTeam(HORDE)); + if (GetStatus() == STATUS_WAIT_LEAVE) - { - data << uint8(1); // bg ended - data << uint8(GetWinner()); // who win - } - else - data << uint8(0); // bg not ended + data << uint8(GetWinner()); - data << uint32(GetPlayerScoresSize()); - for (auto const& score : PlayerScores) - score.second->AppendToPacket(data); + data << uint8(GetPlayersCountByTeam(ALLIANCE)); } bool Battleground::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor) @@ -1302,6 +1395,7 @@ bool Battleground::AddObject(uint32 type, uint32 entry, float x, float y, float delete go; return false; } + /* uint32 guid = go->GetGUIDLow(); @@ -1514,6 +1608,7 @@ bool Battleground::AddSpiritGuide(uint32 type, float x, float y, float z, float creature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL); // correct cast speed creature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); + creature->SetFloatValue(UNIT_MOD_CAST_HASTE, 1.0f); //creature->CastSpell(creature, SPELL_SPIRIT_HEAL_CHANNEL, true); return true; } @@ -1590,7 +1685,7 @@ void Battleground::EndNow() { RemoveFromBGFreeSlotQueue(); SetStatus(STATUS_WAIT_LEAVE); - SetEndTime(0); + SetRemainingTime(0); } // To be removed @@ -1710,7 +1805,7 @@ void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player) BuildPvPLogDataPacket(data); player->SendDirectMessage(&data); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBGTeam()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, player->GetBattlegroundQueueJoinTime(GetTypeID()), GetElapsedTime(), GetArenaType()); player->SendDirectMessage(&data); } diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index c2e5b03e3ae..d04ff5171aa 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -118,12 +118,14 @@ enum BattlegroundTimeIntervals RESURRECTION_INTERVAL = 30000, // ms //REMIND_INTERVAL = 10000, // ms INVITATION_REMIND_TIME = 20000, // ms - INVITE_ACCEPT_WAIT_TIME = 60000, // ms - TIME_TO_AUTOREMOVE = 120000, // ms + INVITE_ACCEPT_WAIT_TIME = 90000, // ms + TIME_AUTOCLOSE_BATTLEGROUND = 120000, // ms MAX_OFFLINE_TIME = 300, // secs RESPAWN_ONE_DAY = 86400, // secs RESPAWN_IMMEDIATELY = 0, // secs - BUFF_RESPAWN_TIME = 180 // secs + BUFF_RESPAWN_TIME = 180, // secs + BATTLEGROUND_COUNTDOWN_MAX = 120, // secs + ARENA_COUNTDOWN_MAX = 60 // secs }; enum BattlegroundStartTimeIntervals @@ -142,7 +144,7 @@ enum BattlegroundBuffObjects BG_OBJECTID_BERSERKERBUFF_ENTRY = 179905 }; -const uint32 Buff_Entries[3] = { BG_OBJECTID_SPEEDBUFF_ENTRY, BG_OBJECTID_REGENBUFF_ENTRY, BG_OBJECTID_BERSERKERBUFF_ENTRY }; +uint32 const Buff_Entries[3] = { BG_OBJECTID_SPEEDBUFF_ENTRY, BG_OBJECTID_REGENBUFF_ENTRY, BG_OBJECTID_BERSERKERBUFF_ENTRY }; enum BattlegroundStatus { @@ -157,6 +159,7 @@ struct BattlegroundPlayer { time_t OfflineRemoveTime; // for tracking and removing offline players from queue after 5 minutes uint32 Team; // Player's team + int32 PrimaryTree; // Player's primary tree }; struct BattlegroundObjectInfo @@ -237,13 +240,14 @@ class Battleground /* Battleground */ // Get methods: std::string const& GetName() const { return m_Name; } + uint64 GetGUID() { return m_Guid; } BattlegroundTypeId GetTypeID(bool GetRandom = false) const { return GetRandom ? m_RandomTypeID : m_TypeID; } BattlegroundBracketId GetBracketId() const { return m_BracketId; } uint32 GetInstanceID() const { return m_InstanceID; } BattlegroundStatus GetStatus() const { return m_Status; } uint32 GetClientInstanceID() const { return m_ClientInstanceID; } - uint32 GetStartTime() const { return m_StartTime; } - uint32 GetEndTime() const { return m_EndTime; } + uint32 GetElapsedTime() const { return m_StartTime; } + uint32 GetRemainingTime() const { return m_EndTime; } uint32 GetLastResurrectTime() const { return m_LastResurrectTime; } uint32 GetMaxPlayers() const { return m_MaxPlayers; } uint32 GetMinPlayers() const { return m_MinPlayers; } @@ -262,6 +266,7 @@ class Battleground bool IsRandom() const { return m_IsRandom; } // Set methods: + void SetGuid(uint64 newGuid) { m_Guid = newGuid; } void SetName(std::string const& name) { m_Name = name; } void SetTypeID(BattlegroundTypeId TypeID) { m_TypeID = TypeID; } void SetRandomTypeID(BattlegroundTypeId TypeID) { m_RandomTypeID = TypeID; } @@ -270,8 +275,8 @@ class Battleground void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; } void SetStatus(BattlegroundStatus Status) { m_Status = Status; } void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; } - void SetStartTime(uint32 Time) { m_StartTime = Time; } - void SetEndTime(uint32 Time) { m_EndTime = Time; } + void SetElapsedTime(uint32 Time) { m_StartTime = Time; } + void SetRemainingTime(uint32 Time) { m_EndTime = Time; } void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; } void SetMaxPlayers(uint32 MaxPlayers) { m_MaxPlayers = MaxPlayers; } void SetMinPlayers(uint32 MinPlayers) { m_MinPlayers = MinPlayers; } @@ -519,6 +524,7 @@ class Battleground BattlegroundStatus m_Status; uint32 m_ClientInstanceID; // the instance-id which is sent to the client and without any other internal use uint32 m_StartTime; + uint32 m_CountdownTimer; uint32 m_ResetStatTimer; uint32 m_ValidStartPositionTimer; int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself @@ -534,6 +540,7 @@ class Battleground bool m_PrematureCountDown; uint32 m_PrematureCountDownTimer; std::string m_Name; + uint64 m_Guid; /* Pre- and post-update hooks */ diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index 82ea0901875..45111a80bc5 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -35,6 +35,8 @@ #include "BattlegroundDS.h" #include "BattlegroundRV.h" #include "BattlegroundIC.h" +#include "BattlegroundTP.h" +#include "BattlegroundBFG.h" #include "Chat.h" #include "Map.h" #include "MapInstanced.h" @@ -52,8 +54,7 @@ BattlegroundMgr::BattlegroundMgr() : m_NextRatedArenaUpdate(sWorld->getIntConfig(CONFIG_ARENA_RATED_UPDATE_TIMER)), - m_NextAutoDistributionTime(0), - m_AutoDistributionTimeChecker(0), m_ArenaTesting(false), m_Testing(false) + m_ArenaTesting(false), m_Testing(false) { } BattlegroundMgr::~BattlegroundMgr() @@ -145,83 +146,284 @@ void BattlegroundMgr::Update(uint32 diff) else m_NextRatedArenaUpdate -= diff; } - - if (sWorld->getBoolConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS)) - { - if (m_AutoDistributionTimeChecker < diff) - { - if (time(NULL) > m_NextAutoDistributionTime) - { - sArenaTeamMgr->DistributeArenaPoints(); - m_NextAutoDistributionTime = m_NextAutoDistributionTime + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld->getIntConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS); - sWorld->setWorldState(WS_ARENA_DISTRIBUTION_TIME, uint64(m_NextAutoDistributionTime)); - } - m_AutoDistributionTimeChecker = 600000; // check 10 minutes - } - else - m_AutoDistributionTimeChecker -= diff; - } } -void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype, uint32 arenaFaction) +void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, Player* player, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype) { - // we can be in 2 queues in same time... + ObjectGuid playerGuid = player->GetGUID(); + ObjectGuid bgGuid; - if (StatusID == 0 || !bg) - { - data->Initialize(SMSG_BATTLEFIELD_STATUS, 4+8); - *data << uint32(QueueSlot); // queue id (0...1) - *data << uint64(0); - return; - } + if (bg) + bgGuid = bg->GetGUID(); + else + StatusID = STATUS_NONE; - data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+8+1+1+4+1+4+4+4)); - *data << uint32(QueueSlot); // queue id (0...1) - player can be in 2 queues in time - // The following segment is read as uint64 in client but can be appended as their original type. - *data << uint8(arenatype); - TC_LOG_DEBUG("network", "BattlegroundMgr::BuildBattlegroundStatusPacket: arenatype = %u for bg instanceID %u, TypeID %u.", arenatype, bg->GetClientInstanceID(), bg->GetTypeID()); - *data << uint8(bg->isArena() ? 0xE : 0x0); - *data << uint32(bg->GetTypeID()); - *data << uint16(0x1F90); - // End of uint64 segment, decomposed this way for simplicity - *data << uint8(bg->GetMinLevel()); - *data << uint8(bg->GetMaxLevel()); - *data << uint32(bg->GetClientInstanceID()); - // alliance/horde for BG and skirmish/rated for Arenas - // following displays the minimap-icon 0 = faction icon 1 = arenaicon - *data << uint8(bg->isRated()); // 1 for rated match, 0 for bg or non rated match - - *data << uint32(StatusID); // status switch (StatusID) { - case STATUS_WAIT_QUEUE: // status_in_queue - *data << uint32(Time1); // average wait time, milliseconds - *data << uint32(Time2); // time in queue, updated every minute!, milliseconds + case STATUS_NONE: + { + data->Initialize(SMSG_BATTLEFIELD_STATUS); + + data->WriteBit(playerGuid[0]); + data->WriteBit(playerGuid[4]); + data->WriteBit(playerGuid[7]); + data->WriteBit(playerGuid[1]); + data->WriteBit(playerGuid[6]); + data->WriteBit(playerGuid[3]); + data->WriteBit(playerGuid[5]); + data->WriteBit(playerGuid[2]); + + data->WriteByteSeq(playerGuid[5]); + data->WriteByteSeq(playerGuid[6]); + data->WriteByteSeq(playerGuid[7]); + data->WriteByteSeq(playerGuid[2]); + *data << uint32(1); // unk, always 1 + data->WriteByteSeq(playerGuid[3]); + data->WriteByteSeq(playerGuid[1]); + *data << uint32(QueueSlot); // Queue slot + *data << uint32(Time1); // Join Time + data->WriteByteSeq(playerGuid[0]); + data->WriteByteSeq(playerGuid[4]); break; - case STATUS_WAIT_JOIN: // status_invite - *data << uint32(bg->GetMapId()); // map id - *data << uint64(0); // 3.3.5, unknown - *data << uint32(Time1); // time to remove from queue, milliseconds + } + case STATUS_WAIT_QUEUE: + { + data->Initialize(SMSG_BATTLEFIELD_STATUS_QUEUED); + + data->WriteBit(playerGuid[3]); + data->WriteBit(playerGuid[0]); + data->WriteBit(bgGuid[3]); + data->WriteBit(playerGuid[2]); + data->WriteBit(1); // Eligible In Queue + data->WriteBit(0); // Join Failed, 1 when it's arena ... + data->WriteBit(bgGuid[2]); + data->WriteBit(playerGuid[1]); + data->WriteBit(bgGuid[0]); + data->WriteBit(bgGuid[6]); + data->WriteBit(bgGuid[4]); + data->WriteBit(playerGuid[6]); + data->WriteBit(playerGuid[7]); + data->WriteBit(bgGuid[7]); + data->WriteBit(bgGuid[5]); + data->WriteBit(playerGuid[4]); + data->WriteBit(playerGuid[5]); + data->WriteBit(bg->isRated()); // Is Rated + data->WriteBit(0); // Waiting On Other Activity + data->WriteBit(bgGuid[1]); + + data->FlushBits(); + + data->WriteByteSeq(playerGuid[0]); + *data << uint32(bg->isArena() ? arenatype : 1); // Player count, 1 for bgs, 2-3-5 for arena (2v2, 3v3, 5v5) + data->WriteByteSeq(bgGuid[5]); + data->WriteByteSeq(playerGuid[3]); + *data << uint32(Time1); // Estimated Wait Time + data->WriteByteSeq(bgGuid[7]); + data->WriteByteSeq(bgGuid[1]); + data->WriteByteSeq(bgGuid[2]); + *data << uint8(0); // unk + data->WriteByteSeq(bgGuid[4]); + data->WriteByteSeq(playerGuid[2]); + *data << uint8(0); // unk + data->WriteByteSeq(bgGuid[6]); + data->WriteByteSeq(playerGuid[7]); + data->WriteByteSeq(bgGuid[3]); + data->WriteByteSeq(playerGuid[6]); + data->WriteByteSeq(bgGuid[0]); + *data << uint32(Time2); // Join Time + *data << uint32(QueueSlot); // Queue slot + *data << uint8(bg->GetMinLevel()); // Min Level + *data << uint32(GetMSTimeDiffToNow(Time2)); // Time since joined + data->WriteByteSeq(playerGuid[1]); + data->WriteByteSeq(playerGuid[5]); + *data << uint32(bg->GetClientInstanceID()); // Client Instance ID + data->WriteByteSeq(playerGuid[4]); break; - case STATUS_IN_PROGRESS: // status_in_progress - *data << uint32(bg->GetMapId()); // map id - *data << uint64(0); // 3.3.5, unknown - *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds - *data << uint32(Time2); // time from bg start, milliseconds - *data << uint8(arenaFaction == ALLIANCE ? 1 : 0); // arenafaction (0 for horde, 1 for alliance) + } + case STATUS_WAIT_JOIN: + { + data->Initialize(SMSG_BATTLEFIELD_STATUS_NEEDCONFIRMATION); + + *data << uint32(bg->GetClientInstanceID()); // Client Instance ID + *data << uint32(Time1); // Time until closed + *data << uint8(0); // unk + *data << uint32(QueueSlot); // Queue slot + *data << uint32(Time2); // Join Time + *data << uint8(bg->GetMinLevel()); // Min Level + *data << uint32(bg->isArena() ? arenatype : 1); // Player count, 1 for bgs, 2-3-5 for arena (2v2, 3v3, 5v5) + *data << uint32(bg->GetMapId()); // Map Id + *data << uint8(0); // unk + + data->WriteBit(playerGuid[5]); + data->WriteBit(playerGuid[2]); + data->WriteBit(playerGuid[1]); + data->WriteBit(bgGuid[2]); + data->WriteBit(playerGuid[4]); + data->WriteBit(bgGuid[6]); + data->WriteBit(bgGuid[3]); + data->WriteBit(bg->isRated()); // Is Rated + data->WriteBit(playerGuid[7]); + data->WriteBit(playerGuid[3]); + data->WriteBit(bgGuid[7]); + data->WriteBit(bgGuid[0]); + data->WriteBit(bgGuid[4]); + data->WriteBit(playerGuid[6]); + data->WriteBit(bgGuid[1]); + data->WriteBit(bgGuid[5]); + data->WriteBit(playerGuid[0]); + + data->WriteByteSeq(bgGuid[6]); + data->WriteByteSeq(bgGuid[5]); + data->WriteByteSeq(bgGuid[7]); + data->WriteByteSeq(bgGuid[2]); + data->WriteByteSeq(playerGuid[0]); + data->WriteByteSeq(playerGuid[7]); + data->WriteByteSeq(bgGuid[4]); + data->WriteByteSeq(playerGuid[1]); + data->WriteByteSeq(bgGuid[0]); + data->WriteByteSeq(playerGuid[4]); + data->WriteByteSeq(bgGuid[1]); + data->WriteByteSeq(playerGuid[5]); + data->WriteByteSeq(bgGuid[3]); + data->WriteByteSeq(playerGuid[6]); + data->WriteByteSeq(playerGuid[2]); + data->WriteByteSeq(playerGuid[3]); break; - default: - TC_LOG_ERROR("bg.battleground", "Unknown BG status!"); + } + case STATUS_IN_PROGRESS: + { + data->Initialize(SMSG_BATTLEFIELD_STATUS_ACTIVE); + + data->WriteBit(playerGuid[2]); + data->WriteBit(playerGuid[7]); + data->WriteBit(bgGuid[7]); + data->WriteBit(bgGuid[1]); + data->WriteBit(playerGuid[5]); + data->WriteBit(player->GetBGTeam() == HORDE ? 0 : 1); + data->WriteBit(bgGuid[0]); + data->WriteBit(playerGuid[1]); + data->WriteBit(bgGuid[3]); + data->WriteBit(playerGuid[6]); + data->WriteBit(bgGuid[5]); + data->WriteBit(bg->isRated()); // Is Rated + data->WriteBit(playerGuid[4]); + data->WriteBit(bgGuid[6]); + data->WriteBit(bgGuid[4]); + data->WriteBit(bgGuid[2]); + data->WriteBit(playerGuid[3]); + data->WriteBit(playerGuid[0]); + + data->FlushBits(); + + data->WriteByteSeq(bgGuid[4]); + data->WriteByteSeq(bgGuid[5]); + data->WriteByteSeq(playerGuid[5]); + data->WriteByteSeq(bgGuid[1]); + data->WriteByteSeq(bgGuid[6]); + data->WriteByteSeq(bgGuid[3]); + data->WriteByteSeq(bgGuid[7]); + data->WriteByteSeq(playerGuid[6]); + + *data << uint32(Time1); // Join Time + *data << uint8(0); // unk + + data->WriteByteSeq(playerGuid[4]); + data->WriteByteSeq(playerGuid[1]); + + *data << uint32(QueueSlot); // Queue slot + *data << uint8(0); // unk + *data << uint32(bg->isArena() ? arenatype : 1); // Player count, 1 for bgs, 2-3-5 for arena (2v2, 3v3, 5v5) + *data << uint32(bg->GetMapId()); // Map Id + *data << uint8(bg->GetMinLevel()); // Min Level + *data << uint32(Time2); // Elapsed Time + + data->WriteByteSeq(playerGuid[2]); + *data << uint32(bg->GetRemainingTime()); // Remaining Time + + data->WriteByteSeq(playerGuid[0]); + data->WriteByteSeq(playerGuid[3]); + data->WriteByteSeq(bgGuid[2]); + + *data << uint32(bg->GetClientInstanceID()); // Client Instance ID or faction ? + + data->WriteByteSeq(bgGuid[0]); + data->WriteByteSeq(playerGuid[7]); + break; + } + case STATUS_WAIT_LEAVE: break; } } -void BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result) +void BattlegroundMgr::BuildStatusFailedPacket(WorldPacket* data, Battleground* bg, Player* player, uint8 QueueSlot, GroupJoinBattlegroundResult result) { - data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4); - *data << int32(result); - if (result == ERR_BATTLEGROUND_JOIN_TIMED_OUT || result == ERR_BATTLEGROUND_JOIN_FAILED) - *data << uint64(0); // player guid + ObjectGuid guidBytes1 = player->GetGUID(); // player who caused the error + ObjectGuid guidBytes2 = bg->GetGUID(); + ObjectGuid unkGuid3 = 0; + + data->Initialize(SMSG_BATTLEFIELD_STATUS_FAILED); + + data->WriteBit(guidBytes2[3]); + data->WriteBit(unkGuid3[3]); + data->WriteBit(guidBytes1[3]); + data->WriteBit(unkGuid3[0]); + data->WriteBit(guidBytes2[6]); + data->WriteBit(guidBytes1[5]); + data->WriteBit(guidBytes1[6]); + data->WriteBit(guidBytes1[4]); + + data->WriteBit(guidBytes1[2]); + data->WriteBit(unkGuid3[1]); + data->WriteBit(guidBytes2[1]); + data->WriteBit(unkGuid3[5]); + data->WriteBit(unkGuid3[6]); + data->WriteBit(guidBytes1[1]); + data->WriteBit(guidBytes2[7]); + data->WriteBit(unkGuid3[4]); + + data->WriteBit(guidBytes2[2]); + data->WriteBit(guidBytes2[5]); + data->WriteBit(unkGuid3[7]); + data->WriteBit(guidBytes2[4]); + data->WriteBit(guidBytes2[0]); + data->WriteBit(guidBytes1[0]); + data->WriteBit(unkGuid3[2]); + data->WriteBit(guidBytes1[7]); + + data->WriteByteSeq(guidBytes2[1]); + + *data << uint32(1); // Unk, always 1 + *data << uint32(QueueSlot); // Queue slot + + data->WriteByteSeq(guidBytes1[6]); + data->WriteByteSeq(guidBytes1[3]); + data->WriteByteSeq(guidBytes1[7]); + data->WriteByteSeq(guidBytes1[4]); + data->WriteByteSeq(guidBytes2[0]); + data->WriteByteSeq(guidBytes1[5]); + data->WriteByteSeq(guidBytes2[7]); + data->WriteByteSeq(guidBytes2[6]); + data->WriteByteSeq(guidBytes2[2]); + data->WriteByteSeq(unkGuid3[6]); + data->WriteByteSeq(unkGuid3[3]); + data->WriteByteSeq(guidBytes1[1]); + data->WriteByteSeq(guidBytes2[3]); + data->WriteByteSeq(unkGuid3[0]); + data->WriteByteSeq(unkGuid3[1]); + data->WriteByteSeq(unkGuid3[4]); + data->WriteByteSeq(guidBytes1[0]); + data->WriteByteSeq(guidBytes2[5]); + data->WriteByteSeq(unkGuid3[7]); + data->WriteByteSeq(guidBytes2[4]); + data->WriteByteSeq(guidBytes1[2]); + + *data << uint32(result); // Result + + data->WriteByteSeq(unkGuid3[2]); + + *data << uint32(player->GetBattlegroundQueueJoinTime(bg->GetTypeID())); // Join Time + + data->WriteByteSeq(unkGuid3[5]); } void BattlegroundMgr::BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value) @@ -235,18 +437,57 @@ void BattlegroundMgr::BuildPlaySoundPacket(WorldPacket* data, uint32 soundid) { data->Initialize(SMSG_PLAY_SOUND, 4); *data << uint32(soundid); + *data << uint64(0); } void BattlegroundMgr::BuildPlayerLeftBattlegroundPacket(WorldPacket* data, uint64 guid) { + ObjectGuid guidBytes = guid; + data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8); - *data << uint64(guid); + + data->WriteBit(guidBytes[7]); + data->WriteBit(guidBytes[6]); + data->WriteBit(guidBytes[2]); + data->WriteBit(guidBytes[4]); + data->WriteBit(guidBytes[5]); + data->WriteBit(guidBytes[1]); + data->WriteBit(guidBytes[3]); + data->WriteBit(guidBytes[0]); + + data->WriteByteSeq(guidBytes[4]); + data->WriteByteSeq(guidBytes[2]); + data->WriteByteSeq(guidBytes[5]); + data->WriteByteSeq(guidBytes[7]); + data->WriteByteSeq(guidBytes[0]); + data->WriteByteSeq(guidBytes[6]); + data->WriteByteSeq(guidBytes[1]); + data->WriteByteSeq(guidBytes[3]); } -void BattlegroundMgr::BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, Player* player) +void BattlegroundMgr::BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, uint64 guid) { + ObjectGuid guidBytes = guid; + data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8); - *data << uint64(player->GetGUID()); + + data->WriteBit(guidBytes[0]); + data->WriteBit(guidBytes[4]); + data->WriteBit(guidBytes[3]); + data->WriteBit(guidBytes[5]); + data->WriteBit(guidBytes[7]); + data->WriteBit(guidBytes[6]); + data->WriteBit(guidBytes[2]); + data->WriteBit(guidBytes[1]); + + data->WriteByteSeq(guidBytes[1]); + data->WriteByteSeq(guidBytes[5]); + data->WriteByteSeq(guidBytes[3]); + data->WriteByteSeq(guidBytes[2]); + data->WriteByteSeq(guidBytes[0]); + data->WriteByteSeq(guidBytes[7]); + data->WriteByteSeq(guidBytes[4]); + data->WriteByteSeq(guidBytes[6]); } Battleground* BattlegroundMgr::GetBattlegroundThroughClientInstance(uint32 instanceId, BattlegroundTypeId bgTypeId) @@ -311,7 +552,7 @@ Battleground* BattlegroundMgr::GetBattlegroundTemplate(BattlegroundTypeId bgType return NULL; BattlegroundContainer const& bgs = itr->second.m_Battlegrounds; - //map is sorted and we can be sure that lowest instance id has only BG template + // map is sorted and we can be sure that lowest instance id has only BG template return bgs.empty() ? NULL : bgs.begin()->second; } @@ -391,6 +632,12 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original case BATTLEGROUND_IC: bg = new BattlegroundIC(*(BattlegroundIC*)bg_template); break; + case BATTLEGROUND_TP: + bg = new BattlegroundTP(*(BattlegroundTP*)bg_template); + break; + case BATTLEGROUND_BFG: + bg = new BattlegroundBFG(*(BattlegroundBFG*)bg_template); + break; case BATTLEGROUND_RB: case BATTLEGROUND_AA: default: @@ -409,6 +656,7 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original bg->SetRandomTypeID(bgTypeId); bg->SetRated(isRated); bg->SetRandom(isRandom); + bg->SetGuid(MAKE_NEW_GUID(bgTypeId, 0, HIGHGUID_BATTLEGROUND)); // Set up correct min/max player counts for scoreboards if (bg->isArena()) @@ -444,45 +692,51 @@ bool BattlegroundMgr::CreateBattleground(BattlegroundTemplate const* bgTemplate) switch (bgTemplate->Id) { case BATTLEGROUND_AV: - bg = new BattlegroundAV(); + bg = new BattlegroundAV; break; case BATTLEGROUND_WS: - bg = new BattlegroundWS(); + bg = new BattlegroundWS; break; case BATTLEGROUND_AB: - bg = new BattlegroundAB(); + bg = new BattlegroundAB; break; case BATTLEGROUND_NA: - bg = new BattlegroundNA(); + bg = new BattlegroundNA; break; case BATTLEGROUND_BE: - bg = new BattlegroundBE(); + bg = new BattlegroundBE; break; case BATTLEGROUND_EY: - bg = new BattlegroundEY(); + bg = new BattlegroundEY; break; case BATTLEGROUND_RL: - bg = new BattlegroundRL(); + bg = new BattlegroundRL; break; case BATTLEGROUND_SA: - bg = new BattlegroundSA(); + bg = new BattlegroundSA; break; case BATTLEGROUND_DS: - bg = new BattlegroundDS(); + bg = new BattlegroundDS; break; case BATTLEGROUND_RV: - bg = new BattlegroundRV(); + bg = new BattlegroundRV; break; case BATTLEGROUND_IC: - bg = new BattlegroundIC(); + bg = new BattlegroundIC; break; case BATTLEGROUND_AA: - bg = new Battleground(); + bg = new Battleground; break; case BATTLEGROUND_RB: - bg = new Battleground(); + bg = new Battleground; bg->SetRandom(true); break; + case BATTLEGROUND_TP: + bg = new BattlegroundTP; + break; + case BATTLEGROUND_BFG: + bg = new BattlegroundBFG; + break; default: return false; } @@ -493,17 +747,21 @@ bool BattlegroundMgr::CreateBattleground(BattlegroundTemplate const* bgTemplate) } bg->SetMapId(bgTemplate->BattlemasterEntry->mapid[0]); - bg->SetName(bgTemplate->BattlemasterEntry->name[sWorld->GetDefaultDbcLocale()]); + bg->SetName(bgTemplate->BattlemasterEntry->name); + bg->SetInstanceID(0); bg->SetArenaorBGType(bgTemplate->IsArena()); bg->SetMinPlayersPerTeam(bgTemplate->MinPlayersPerTeam); bg->SetMaxPlayersPerTeam(bgTemplate->MaxPlayersPerTeam); bg->SetMinPlayers(bgTemplate->MinPlayersPerTeam * 2); bg->SetMaxPlayers(bgTemplate->MaxPlayersPerTeam * 2); bg->SetTeamStartPosition(TEAM_ALLIANCE, bgTemplate->StartLocation[TEAM_ALLIANCE]); - bg->SetTeamStartPosition(TEAM_HORDE, bgTemplate->StartLocation[TEAM_HORDE]); + bg->SetTeamStartPosition(TEAM_HORDE, bgTemplate->StartLocation[TEAM_HORDE]); bg->SetStartMaxDist(bgTemplate->MaxStartDistSq); bg->SetLevelRange(bgTemplate->MinLevel, bgTemplate->MaxLevel); bg->SetScriptId(bgTemplate->ScriptId); + bg->SetGuid(MAKE_NEW_GUID(bgTemplate->Id, 0, HIGHGUID_BATTLEGROUND)); + + AddBattleground(bg); return true; } @@ -608,86 +866,75 @@ void BattlegroundMgr::LoadBattlegroundTemplates() TC_LOG_INFO("server.loading", ">> Loaded %u battlegrounds in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void BattlegroundMgr::InitAutomaticArenaPointDistribution() +void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, uint64 guid, Player* player, BattlegroundTypeId bgTypeId) { - if (!sWorld->getBoolConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS)) + if (!player) return; - time_t wstime = time_t(sWorld->getWorldState(WS_ARENA_DISTRIBUTION_TIME)); - time_t curtime = time(NULL); - TC_LOG_DEBUG("bg.battleground", "Initializing Automatic Arena Point Distribution"); - if (wstime < curtime) - { - m_NextAutoDistributionTime = curtime; // reset will be called in the next update - TC_LOG_DEBUG("bg.battleground", "Battleground: Next arena point distribution time in the past, reseting it now."); - } - else - m_NextAutoDistributionTime = wstime; - TC_LOG_DEBUG("bg.battleground", "Automatic Arena Point Distribution initialized."); -} + BattlegroundDataContainer::iterator it = bgDataStore.find(bgTypeId); + if (it == bgDataStore.end()) + return; -void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, uint64 guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere) -{ - if (!player) + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(it->second.m_Battlegrounds.begin()->second->GetMapId(), player->getLevel()); + if (!bracketEntry) return; - uint32 winner_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST); - uint32 winner_arena = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_FIRST); - uint32 loser_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST); + uint32 winnerConquest = (player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_CONQUEST_FIRST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_CONQUEST_LAST)) / CURRENCY_PRECISION; + uint32 winnerHonor = (player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST)) / CURRENCY_PRECISION; + uint32 loserHonor = (!player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST)) / CURRENCY_PRECISION; - winner_kills = Trinity::Honor::hk_honor_at_level(player->getLevel(), float(winner_kills)); - loser_kills = Trinity::Honor::hk_honor_at_level(player->getLevel(), float(loser_kills)); + ObjectGuid guidBytes = guid; data->Initialize(SMSG_BATTLEFIELD_LIST); - *data << uint64(guid); // battlemaster guid - *data << uint8(fromWhere); // from where you joined - *data << uint32(bgTypeId); // battleground id - *data << uint8(0); // unk - *data << uint8(0); // unk - - // Rewards - *data << uint8(player->GetRandomWinner()); // 3.3.3 hasWin - *data << uint32(winner_kills); // 3.3.3 winHonor - *data << uint32(winner_arena); // 3.3.3 winArena - *data << uint32(loser_kills); // 3.3.3 lossHonor - - uint8 isRandom = bgTypeId == BATTLEGROUND_RB; - - *data << uint8(isRandom); // 3.3.3 isRandom - if (isRandom) - { - // Rewards (random) - *data << uint8(player->GetRandomWinner()); // 3.3.3 hasWin_Random - *data << uint32(winner_kills); // 3.3.3 winHonor_Random - *data << uint32(winner_arena); // 3.3.3 winArena_Random - *data << uint32(loser_kills); // 3.3.3 lossHonor_Random - } + *data << uint32(winnerConquest) // Winner Conquest Reward or Random Winner Conquest Reward + << uint32(winnerConquest) // Winner Conquest Reward or Random Winner Conquest Reward + << uint32(loserHonor) // Loser Honor Reward or Random Loser Honor Reward + << uint32(bgTypeId) // battleground id + << uint32(loserHonor) // Loser Honor Reward or Random Loser Honor Reward + << uint32(winnerHonor) // Winner Honor Reward or Random Winner Honor Reward + << uint32(winnerHonor) // Winner Honor Reward or Random Winner Honor Reward + << uint8(bracketEntry->maxLevel) // max level + << uint8(bracketEntry->minLevel); // min level + + data->WriteBit(guidBytes[0]); + data->WriteBit(guidBytes[1]); + data->WriteBit(guidBytes[7]); + data->WriteBit(0); // unk + data->WriteBit(0); // unk + + data->FlushBits(); + size_t count_pos = data->bitwpos(); + data->WriteBits(0, 24); // placeholder + + data->WriteBit(guidBytes[6]); + data->WriteBit(guidBytes[4]); + data->WriteBit(guidBytes[2]); + data->WriteBit(guidBytes[3]); + data->WriteBit(0); // unk + data->WriteBit(guidBytes[5]); + data->WriteBit(0); // unk + + data->FlushBits(); + + data->WriteByteSeq(guidBytes[6]); + data->WriteByteSeq(guidBytes[1]); + data->WriteByteSeq(guidBytes[7]); + data->WriteByteSeq(guidBytes[5]); - if (bgTypeId == BATTLEGROUND_AA) // arena - *data << uint32(0); // unk (count?) - else // battleground + uint32 count = 0; + BattlegroundBracketId bracketId = bracketEntry->GetBracketId(); + BattlegroundClientIdsContainer& clientIds = it->second.m_ClientBattlegroundIds[bracketId]; + for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end(); ++itr) { - size_t count_pos = data->wpos(); - *data << uint32(0); // number of bg instances - - BattlegroundDataContainer::iterator it = bgDataStore.find(bgTypeId); - if (it != bgDataStore.end()) - { - // expected bracket entry - if (PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(it->second.m_Battlegrounds.begin()->second->GetMapId(), player->getLevel())) - { - uint32 count = 0; - BattlegroundBracketId bracketId = bracketEntry->GetBracketId(); - BattlegroundClientIdsContainer& clientIds = it->second.m_ClientBattlegroundIds[bracketId]; - for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end(); ++itr) - { - *data << uint32(*itr); - ++count; - } - data->put<uint32>(count_pos, count); - } - } + *data << uint32(*itr); + ++count; } + data->PutBits(count_pos, count, 24); // bg instance count + + data->WriteByteSeq(guidBytes[0]); + data->WriteByteSeq(guidBytes[2]); + data->WriteByteSeq(guidBytes[4]); + data->WriteByteSeq(guidBytes[3]); } void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId bgTypeId) @@ -696,8 +943,6 @@ void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, Batt { uint32 mapid = bg->GetMapId(); uint32 team = player->GetBGTeam(); - if (team == 0) - team = player->GetTeam(); Position const* pos = bg->GetTeamStartPosition(Battleground::GetTeamIndexByTeamId(team)); TC_LOG_DEBUG("bg.battleground", "BattlegroundMgr::SendToBattleground: Sending %s to map %u, %s (bgType %u)", player->GetName().c_str(), mapid, pos->ToString().c_str(), bgTypeId); @@ -739,6 +984,10 @@ BattlegroundQueueTypeId BattlegroundMgr::BGQueueTypeId(BattlegroundTypeId bgType return BATTLEGROUND_QUEUE_EY; case BATTLEGROUND_IC: return BATTLEGROUND_QUEUE_IC; + case BATTLEGROUND_TP: + return BATTLEGROUND_QUEUE_TP; + case BATTLEGROUND_BFG: + return BATTLEGROUND_QUEUE_BFG; case BATTLEGROUND_RB: return BATTLEGROUND_QUEUE_RB; case BATTLEGROUND_SA: @@ -783,6 +1032,10 @@ BattlegroundTypeId BattlegroundMgr::BGTemplateId(BattlegroundQueueTypeId bgQueue return BATTLEGROUND_SA; case BATTLEGROUND_QUEUE_IC: return BATTLEGROUND_IC; + case BATTLEGROUND_QUEUE_TP: + return BATTLEGROUND_TP; + case BATTLEGROUND_QUEUE_BFG: + return BATTLEGROUND_BFG; case BATTLEGROUND_QUEUE_RB: return BATTLEGROUND_RB; case BATTLEGROUND_QUEUE_2v2: @@ -929,6 +1182,8 @@ HolidayIds BattlegroundMgr::BGTypeToWeekendHolidayId(BattlegroundTypeId bgTypeId case BATTLEGROUND_SA: return HOLIDAY_CALL_TO_ARMS_SA; case BATTLEGROUND_AB: return HOLIDAY_CALL_TO_ARMS_AB; case BATTLEGROUND_IC: return HOLIDAY_CALL_TO_ARMS_IC; + case BATTLEGROUND_TP: return HOLIDAY_CALL_TO_ARMS_TP; + case BATTLEGROUND_BFG: return HOLIDAY_CALL_TO_ARMS_BFG; default: return HOLIDAY_NONE; } } @@ -943,6 +1198,8 @@ BattlegroundTypeId BattlegroundMgr::WeekendHolidayIdToBGType(HolidayIds holiday) case HOLIDAY_CALL_TO_ARMS_SA: return BATTLEGROUND_SA; case HOLIDAY_CALL_TO_ARMS_AB: return BATTLEGROUND_AB; case HOLIDAY_CALL_TO_ARMS_IC: return BATTLEGROUND_IC; + case HOLIDAY_CALL_TO_ARMS_TP: return BATTLEGROUND_TP; + case HOLIDAY_CALL_TO_ARMS_BFG: return BATTLEGROUND_BFG; default: return BATTLEGROUND_TYPE_NONE; } } @@ -1024,4 +1281,3 @@ void BattlegroundMgr::RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 ins { bgDataStore[bgTypeId].m_Battlegrounds.erase(instanceId); } - diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index c21c34d1a10..e6f8eee354e 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -29,8 +29,7 @@ typedef std::set<uint32> BattlegroundClientIdsContainer; typedef std::unordered_map<uint32, BattlegroundTypeId> BattleMastersMap; -#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day -#define WS_ARENA_DISTRIBUTION_TIME 20001 // Custom worldstate +#define WS_CURRENCY_RESET_TIME 20001 // Custom worldstate struct BattlegroundData { @@ -71,12 +70,12 @@ class BattlegroundMgr void Update(uint32 diff); /* Packet Building */ - void BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, Player* player); + void BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, uint64 guid); void BuildPlayerLeftBattlegroundPacket(WorldPacket* data, uint64 guid); - void BuildBattlegroundListPacket(WorldPacket* data, uint64 guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere); - void BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result); + void BuildBattlegroundListPacket(WorldPacket* data, uint64 guid, Player* player, BattlegroundTypeId bgTypeId); + void BuildStatusFailedPacket(WorldPacket* data, Battleground* bg, Player* pPlayer, uint8 QueueSlot, GroupJoinBattlegroundResult result); void BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value); - void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, uint32 arenaFaction); + void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, Player* player, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType); void BuildPlaySoundPacket(WorldPacket* data, uint32 soundId); void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, uint64 guid); @@ -120,7 +119,6 @@ class BattlegroundMgr uint32 GetMaxRatingDifference() const; uint32 GetRatingDiscardTimer() const; - void InitAutomaticArenaPointDistribution(); void LoadBattleMastersEntry(); void CheckBattleMasters(); BattlegroundTypeId GetBattleMasterBG(uint32 entry) const @@ -144,8 +142,6 @@ class BattlegroundMgr std::vector<uint64> m_QueueUpdateScheduler; uint32 m_NextRatedArenaUpdate; - time_t m_NextAutoDistributionTime; - uint32 m_AutoDistributionTimeChecker; bool m_ArenaTesting; bool m_Testing; BattleMastersMap mBattleMastersMap; diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp index e52f75a1c41..2b9713157c9 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp +++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp @@ -390,10 +390,11 @@ void BattlegroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount) Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(group->BgTypeId); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType); uint32 queueSlot = plr2->GetBattlegroundQueueIndex(bgQueueTypeId); + plr2->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to // queue->removeplayer, it causes bugs WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, plr2, queueSlot, STATUS_NONE, plr2->GetBattlegroundQueueJoinTime(group->BgTypeId), 0, 0); plr2->GetSession()->SendPacket(&data); } // then actually delete, this may delete the group as well! @@ -478,7 +479,7 @@ bool BattlegroundQueue::InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, player->GetName().c_str(), player->GetGUIDLow(), bg->GetInstanceID(), queueSlot, bg->GetTypeID()); // send status packet - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, player, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, player->GetBattlegroundQueueJoinTime(bgTypeId), ginfo->ArenaType); player->GetSession()->SendPacket(&data); } return true; @@ -628,7 +629,7 @@ bool BattlegroundQueue::CheckPremadeMatch(BattlegroundBracketId bracket_id, uint } // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam -bool BattlegroundQueue::CheckNormalMatch(Battleground* bg_template, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers) +bool BattlegroundQueue::CheckNormalMatch(Battleground* /*bg_template*/, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers) { GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT]; for (uint32 i = 0; i < BG_TEAMS_COUNT; i++) @@ -664,7 +665,7 @@ bool BattlegroundQueue::CheckNormalMatch(Battleground* bg_template, Battleground return false; } //allow 1v0 if debug bg - if (sBattlegroundMgr->isTesting() && bg_template->isBattleground() && (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[TEAM_HORDE].GetPlayerCount())) + if (sBattlegroundMgr->isTesting() && (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[TEAM_HORDE].GetPlayerCount())) return true; //return true if there are enough players in selection pools - enable to work .debug bg command correctly return m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[TEAM_HORDE].GetPlayerCount() >= minPlayers; @@ -1000,7 +1001,7 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) { WorldPacket data; //we must send remaining time in queue - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_ArenaType, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, player, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, player->GetBattlegroundQueueJoinTime(m_BgTypeId), m_ArenaType); player->GetSession()->SendPacket(&data); } } @@ -1048,7 +1049,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) sBattlegroundMgr->ScheduleQueueUpdate(0, 0, m_BgQueueTypeId, m_BgTypeId, bg->GetBracketId()); WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, player, queueSlot, STATUS_NONE, player->GetBattlegroundQueueJoinTime(m_BgTypeId), 0, 0); player->GetSession()->SendPacket(&data); } } diff --git a/src/server/game/Battlegrounds/BattlegroundScore.h b/src/server/game/Battlegrounds/BattlegroundScore.h index 81aca355be8..23e06693e56 100644 --- a/src/server/game/Battlegrounds/BattlegroundScore.h +++ b/src/server/game/Battlegrounds/BattlegroundScore.h @@ -19,6 +19,8 @@ #define TRINITY_BATTLEGROUND_SCORE_H #include "WorldPacket.h" +#include "Player.h" +#include "ObjectAccessor.h" enum ScoreType { @@ -29,7 +31,7 @@ enum ScoreType SCORE_DAMAGE_DONE = 5, SCORE_HEALING_DONE = 6, - // WS and EY + // WS, EY and TP SCORE_FLAG_CAPTURES = 7, SCORE_FLAG_RETURNS = 8, @@ -55,8 +57,8 @@ struct BattlegroundScore friend class Battleground; protected: - BattlegroundScore(uint64 playerGuid) : PlayerGuid(playerGuid), KillingBlows(0), Deaths(0), - HonorableKills(0), BonusHonor(0), DamageDone(0), HealingDone(0) { } + BattlegroundScore(uint64 playerGuid, uint32 team) : PlayerGuid(playerGuid), TeamId(team == ALLIANCE ? 1 : 0), + KillingBlows(0), Deaths(0), HonorableKills(0), BonusHonor(0), DamageDone(0), HealingDone(0) { } virtual ~BattlegroundScore() { } @@ -88,26 +90,77 @@ struct BattlegroundScore } } - virtual void AppendToPacket(WorldPacket& data) + virtual void AppendToPacket(WorldPacket& data, ByteBuffer& content) { - data << uint64(PlayerGuid); + uint32 primaryTree = 0; + if (Player* player = ObjectAccessor::FindPlayer(PlayerGuid)) + primaryTree = player->GetPrimaryTalentTree(player->GetActiveSpec()); - data << uint32(KillingBlows); - data << uint32(HonorableKills); - data << uint32(Deaths); - data << uint32(BonusHonor); - data << uint32(DamageDone); - data << uint32(HealingDone); + data.WriteBit(0); // Unk 1 + data.WriteBit(0); // Unk 2 + data.WriteBit(PlayerGuid[2]); + data.WriteBit(/*!IsArena*/ 1); // IsArena + data.WriteBit(0); // Unk 4 + data.WriteBit(0); // Unk 5 + data.WriteBit(0); // Unk 6 + data.WriteBit(PlayerGuid[3]); + data.WriteBit(PlayerGuid[0]); + data.WriteBit(PlayerGuid[5]); + data.WriteBit(PlayerGuid[1]); + data.WriteBit(PlayerGuid[6]); + data.WriteBit(TeamId); + data.WriteBit(PlayerGuid[7]); - BuildObjectivesBlock(data); + content << uint32(HealingDone); // healing done + content << uint32(DamageDone); // damage done + + //if (!IsArena) + //{ + content << uint32(BonusHonor / 100); + content << uint32(Deaths); + content << uint32(HonorableKills); + //} + + content.WriteByteSeq(PlayerGuid[4]); + content << uint32(KillingBlows); + + //if (unk 5) + // data << uint32() unk + + content.WriteByteSeq(PlayerGuid[5]); + + //if (unk 6) + // data << uint32() unk + + //if (unk 2) + // data << uint32() unk + + content.WriteByteSeq(PlayerGuid[1]); + content.WriteByteSeq(PlayerGuid[6]); + + content << int32(primaryTree); + + BuildObjectivesBlock(data, content); + + data.WriteBit(PlayerGuid[4]); + + content.WriteByteSeq(PlayerGuid[0]); + content.WriteByteSeq(PlayerGuid[3]); + + //if (unk 4) + // data << uint32() unk + + content.WriteByteSeq(PlayerGuid[7]); + content.WriteByteSeq(PlayerGuid[2]); } - virtual void BuildObjectivesBlock(WorldPacket& /*data*/) = 0; + virtual void BuildObjectivesBlock(WorldPacket& /*data*/, ByteBuffer& /*content*/) = 0; // For Logging purpose virtual std::string ToString() const { return ""; } - uint64 PlayerGuid; + ObjectGuid PlayerGuid; + uint8 TeamId; // Default score, present in every type uint32 KillingBlows; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index 2622ab9501f..91174682218 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -224,7 +224,7 @@ void BattlegroundAB::StartingEventOpenDoors() void BattlegroundAB::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUIDLow()] = new BattlegroundABScore(player->GetGUID()); + PlayerScores[player->GetGUIDLow()] = new BattlegroundABScore(player->GetGUID(), player->GetBGTeam()); } void BattlegroundAB::RemovePlayer(Player* /*player*/, uint64 /*guid*/, uint32 /*team*/) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index a6b4be10fdf..74efe421d35 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -242,7 +242,7 @@ struct BattlegroundABScore final : public BattlegroundScore friend class BattlegroundAB; protected: - BattlegroundABScore(uint64 playerGuid) : BattlegroundScore(playerGuid), BasesAssaulted(0), BasesDefended(0) { } + BattlegroundABScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), BasesAssaulted(0), BasesDefended(0) { } void UpdateScore(uint32 type, uint32 value) override { @@ -260,11 +260,11 @@ struct BattlegroundABScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& content) final { - data << uint32(2); - data << uint32(BasesAssaulted); - data << uint32(BasesDefended); + data.WriteBits(2, 24); // Objectives Count + content << uint32(BasesAssaulted); + content << uint32(BasesDefended); } uint32 BasesAssaulted; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index eafb02f031d..9d55e44d491 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -438,7 +438,7 @@ void BattlegroundAV::StartingEventOpenDoors() void BattlegroundAV::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUIDLow()] = new BattlegroundAVScore(player->GetGUID()); + PlayerScores[player->GetGUIDLow()] = new BattlegroundAVScore(player->GetGUID(), player->GetBGTeam()); } void BattlegroundAV::EndBattleground(uint32 winner) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index feb3c016e55..5255caeda18 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -1531,7 +1531,7 @@ struct BattlegroundAVScore final : public BattlegroundScore friend class BattlegroundAV; protected: - BattlegroundAVScore(uint64 playerGuid) : BattlegroundScore(playerGuid), GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), MinesCaptured(0) { } + BattlegroundAVScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), MinesCaptured(0) { } void UpdateScore(uint32 type, uint32 value) override { @@ -1558,14 +1558,14 @@ struct BattlegroundAVScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& content) final { - data << uint32(5); // Objectives Count - data << uint32(GraveyardsAssaulted); - data << uint32(GraveyardsDefended); - data << uint32(TowersAssaulted); - data << uint32(TowersDefended); - data << uint32(MinesCaptured); + data.WriteBits(5, 24); // Objectives Count + content << uint32(GraveyardsAssaulted); + content << uint32(GraveyardsDefended); + content << uint32(TowersAssaulted); + content << uint32(TowersDefended); + content << uint32(MinesCaptured); } uint32 GraveyardsAssaulted; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBFG.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundBFG.cpp new file mode 100644 index 00000000000..b7e97b406e3 --- /dev/null +++ b/src/server/game/Battlegrounds/Zones/BattlegroundBFG.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Battleground.h" +#include "BattlegroundBFG.h" +#include "Creature.h" +#include "GameObject.h" +#include "Language.h" +#include "Object.h" +#include "ObjectMgr.h" +#include "BattlegroundMgr.h" +#include "Player.h" +#include "World.h" +#include "WorldPacket.h" + +BattlegroundBFG::BattlegroundBFG() +{ +} + +BattlegroundBFG::~BattlegroundBFG() +{ +} diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h b/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h new file mode 100644 index 00000000000..1f539a414b2 --- /dev/null +++ b/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __BATTLEGROUNDBFG_H +#define __BATTLEGROUNDBFG_H + +#include "Battleground.h" +#include "BattlegroundScore.h" + +class BattlegroundBFGScore final : public BattlegroundScore +{ + protected: + BattlegroundBFGScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), BasesAssaulted(0), BasesDefended(0) { } + + void UpdateScore(uint32 type, uint32 value) override + { + switch (type) + { + case SCORE_BASES_ASSAULTED: + BasesAssaulted += value; + break; + case SCORE_BASES_DEFENDED: + BasesDefended += value; + break; + default: + BattlegroundScore::UpdateScore(type, value); + break; + } + } + + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& content) final + { + data.WriteBits(2, 24); // Objectives Count + content << uint32(BasesAssaulted); + content << uint32(BasesDefended); + } + + uint32 BasesAssaulted; + uint32 BasesDefended; +}; + +class BattlegroundBFG : public Battleground +{ + public: + BattlegroundBFG(); + ~BattlegroundBFG(); +}; + +#endif diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index ca96140f5da..c25c915dd7a 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -363,7 +363,7 @@ void BattlegroundEY::UpdatePointsIcons(uint32 Team, uint32 Point) void BattlegroundEY::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUIDLow()] = new BattlegroundEYScore(player->GetGUID()); + PlayerScores[player->GetGUIDLow()] = new BattlegroundEYScore(player->GetGUID(), player->GetBGTeam()); m_PlayersNearPoint[EY_POINTS_MAX].push_back(player->GetGUID()); } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index 056deb3498b..9ea6d30fe51 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -328,7 +328,7 @@ struct BattlegroundEYScore final : public BattlegroundScore friend class BattlegroundEY; protected: - BattlegroundEYScore(uint64 playerGuid) : BattlegroundScore(playerGuid), FlagCaptures(0) { } + BattlegroundEYScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), FlagCaptures(0) { } void UpdateScore(uint32 type, uint32 value) override { @@ -343,10 +343,10 @@ struct BattlegroundEYScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& content) final { - data << uint32(1); // Objectives Count - data << uint32(FlagCaptures); + data.WriteBits(1, 24); // Objectives Count + content << uint32(FlagCaptures); } uint32 FlagCaptures; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index 41a37a8962f..e5de2e86a2e 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -273,7 +273,7 @@ void BattlegroundIC::StartingEventOpenDoors() void BattlegroundIC::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUIDLow()] = new BattlegroundICScore(player->GetGUID()); + PlayerScores[player->GetGUIDLow()] = new BattlegroundICScore(player->GetGUID(), player->GetBGTeam()); if (nodePoint[NODE_TYPE_QUARRY].nodeState == (player->GetTeamId() == TEAM_ALLIANCE ? NODE_STATE_CONTROLLED_A : NODE_STATE_CONTROLLED_H)) player->CastSpell(player, SPELL_QUARRY, true); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h index 0b317cabef3..5153a6fb9cf 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h @@ -853,7 +853,7 @@ struct BattlegroundICScore final : public BattlegroundScore friend class BattlegroundIC; protected: - BattlegroundICScore(uint64 playerGuid) : BattlegroundScore(playerGuid), BasesAssaulted(0), BasesDefended(0) { } + BattlegroundICScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), BasesAssaulted(0), BasesDefended(0) { } void UpdateScore(uint32 type, uint32 value) override { @@ -871,11 +871,11 @@ struct BattlegroundICScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& content) final { - data << uint32(2); // Objectives Count - data << uint32(BasesAssaulted); - data << uint32(BasesDefended); + data.WriteBits(2, 24); // Objectives Count + content << uint32(BasesAssaulted); + content << uint32(BasesDefended); } uint32 BasesAssaulted; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index 15c72b6ac00..10ede74685c 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -301,7 +301,7 @@ void BattlegroundSA::StartShips() { if (Player* p = ObjectAccessor::FindPlayer(itr->first)) { - UpdateData data; + UpdateData data(p->GetMapId()); WorldPacket pkt; GetBGObject(i)->BuildValuesUpdateBlockForPlayer(&data, p); data.BuildPacket(&pkt); @@ -478,7 +478,7 @@ void BattlegroundSA::FillInitialWorldStates(WorldPacket& data) void BattlegroundSA::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUIDLow()] = new BattlegroundSAScore(player->GetGUID()); + PlayerScores[player->GetGUIDLow()] = new BattlegroundSAScore(player->GetGUID(), player->GetBGTeam()); SendTransportInit(player); @@ -486,7 +486,7 @@ void BattlegroundSA::AddPlayer(Player* player) { if (player->GetTeamId() == Attackers) { - player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + //player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); if (urand(0, 1)) player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0); @@ -540,7 +540,7 @@ void BattlegroundSA::TeleportPlayers() if (player->GetTeamId() == Attackers) { - player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + //player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); if (urand(0, 1)) player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0); @@ -977,8 +977,9 @@ void BattlegroundSA::SendTransportInit(Player* player) { if (BgObjects[BG_SA_BOAT_ONE] || BgObjects[BG_SA_BOAT_TWO]) { - UpdateData transData; + UpdateData transData(player->GetMapId()); if (BgObjects[BG_SA_BOAT_ONE]) + GetBGObject(BG_SA_BOAT_ONE)->BuildCreateUpdateBlockForPlayer(&transData, player); if (BgObjects[BG_SA_BOAT_TWO]) GetBGObject(BG_SA_BOAT_TWO)->BuildCreateUpdateBlockForPlayer(&transData, player); @@ -992,7 +993,7 @@ void BattlegroundSA::SendTransportsRemove(Player* player) { if (BgObjects[BG_SA_BOAT_ONE] || BgObjects[BG_SA_BOAT_TWO]) { - UpdateData transData; + UpdateData transData(player->GetMapId()); if (BgObjects[BG_SA_BOAT_ONE]) GetBGObject(BG_SA_BOAT_ONE)->BuildOutOfRangeUpdateBlock(&transData); if (BgObjects[BG_SA_BOAT_TWO]) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h index a3947334417..474a2ff8dc3 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -513,7 +513,7 @@ struct BattlegroundSAScore final : public BattlegroundScore friend class BattlegroundSA; protected: - BattlegroundSAScore(uint64 playerGuid) : BattlegroundScore(playerGuid), DemolishersDestroyed(0), GatesDestroyed(0) { } + BattlegroundSAScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), DemolishersDestroyed(0), GatesDestroyed(0) { } void UpdateScore(uint32 type, uint32 value) override { @@ -531,11 +531,11 @@ struct BattlegroundSAScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& content) final { - data << uint32(2); // Objectives Count - data << uint32(DemolishersDestroyed); - data << uint32(GatesDestroyed); + data.WriteBits(2, 24); // Objectives Count + content << uint32(DemolishersDestroyed); + content << uint32(GatesDestroyed); } uint32 DemolishersDestroyed; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundTP.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundTP.cpp new file mode 100644 index 00000000000..6d4c6ce0bac --- /dev/null +++ b/src/server/game/Battlegrounds/Zones/BattlegroundTP.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Battleground.h" +#include "BattlegroundTP.h" +#include "Creature.h" +#include "GameObject.h" +#include "Language.h" +#include "Object.h" +#include "ObjectMgr.h" +#include "BattlegroundMgr.h" +#include "Player.h" +#include "World.h" +#include "WorldPacket.h" + +BattlegroundTP::BattlegroundTP() +{ +} + +BattlegroundTP::~BattlegroundTP() +{ +} diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundTP.h b/src/server/game/Battlegrounds/Zones/BattlegroundTP.h new file mode 100644 index 00000000000..3d34974d845 --- /dev/null +++ b/src/server/game/Battlegrounds/Zones/BattlegroundTP.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __BATTLEGROUNDTP_H +#define __BATTLEGROUNDTP_H + +#include "Battleground.h" +#include "BattlegroundScore.h" + +class BattlegroundTPScore final : public BattlegroundScore +{ + protected: + BattlegroundTPScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), FlagCaptures(0), FlagReturns(0) { } + + void UpdateScore(uint32 type, uint32 value) override + { + switch (type) + { + case SCORE_FLAG_CAPTURES: + FlagCaptures += value; + break; + case SCORE_FLAG_RETURNS: + FlagReturns += value; + break; + default: + BattlegroundScore::UpdateScore(type, value); + break; + } + } + + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& content) final + { + data.WriteBits(2, 24); // Objectives Count + content << uint32(FlagCaptures); + content << uint32(FlagReturns); + } + + uint32 FlagCaptures; + uint32 FlagReturns; +}; + +class BattlegroundTP : public Battleground +{ + public: + BattlegroundTP(); + ~BattlegroundTP(); +}; + +#endif diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index c50669b137e..bcf7093a640 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -77,7 +77,7 @@ void BattlegroundWS::PostUpdateImpl(uint32 diff) { if (GetStatus() == STATUS_IN_PROGRESS) { - if (GetStartTime() >= 27*MINUTE*IN_MILLISECONDS) + if (GetElapsedTime() >= 27*MINUTE*IN_MILLISECONDS) { if (GetTeamScore(TEAM_ALLIANCE) == 0) { @@ -96,7 +96,7 @@ void BattlegroundWS::PostUpdateImpl(uint32 diff) EndBattleground(ALLIANCE); } // first update needed after 1 minute of game already in progress - else if (GetStartTime() > uint32(_minutesElapsed * MINUTE * IN_MILLISECONDS) + 3 * MINUTE * IN_MILLISECONDS) + else if (GetElapsedTime() > uint32(_minutesElapsed * MINUTE * IN_MILLISECONDS) + 3 * MINUTE * IN_MILLISECONDS) { ++_minutesElapsed; UpdateWorldState(BG_WS_STATE_TIMER, 25 - _minutesElapsed); @@ -229,7 +229,7 @@ void BattlegroundWS::StartingEventOpenDoors() void BattlegroundWS::AddPlayer(Player* player) { Battleground::AddPlayer(player); - PlayerScores[player->GetGUIDLow()] = new BattlegroundWGScore(player->GetGUID()); + PlayerScores[player->GetGUIDLow()] = new BattlegroundWGScore(player->GetGUID(), player->GetBGTeam()); } void BattlegroundWS::RespawnFlag(uint32 Team, bool captured) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h index 3d449580fb9..1c3ee932b76 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h @@ -152,7 +152,7 @@ struct BattlegroundWGScore final : public BattlegroundScore friend class BattlegroundWS; protected: - BattlegroundWGScore(uint64 playerGuid) : BattlegroundScore(playerGuid), FlagCaptures(0), FlagReturns(0) { } + BattlegroundWGScore(uint64 playerGuid, uint32 team) : BattlegroundScore(playerGuid, team), FlagCaptures(0), FlagReturns(0) { } void UpdateScore(uint32 type, uint32 value) override { @@ -170,11 +170,11 @@ struct BattlegroundWGScore final : public BattlegroundScore } } - void BuildObjectivesBlock(WorldPacket& data) final + void BuildObjectivesBlock(WorldPacket& data, ByteBuffer& content) final { - data << uint32(2); // Objectives Count - data << uint32(FlagCaptures); - data << uint32(FlagReturns); + data.WriteBits(2, 24); // Objectives Count + content << uint32(FlagCaptures); + content << uint32(FlagReturns); } uint32 FlagCaptures; diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 532900c0438..abb415e0f64 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -148,6 +148,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/DataStores ${CMAKE_CURRENT_SOURCE_DIR}/DungeonFinding ${CMAKE_CURRENT_SOURCE_DIR}/Entities + ${CMAKE_CURRENT_SOURCE_DIR}/Entities/AreaTrigger ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Creature ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Corpse ${CMAKE_CURRENT_SOURCE_DIR}/Entities/DynamicObject diff --git a/src/server/game/Calendar/CalendarMgr.cpp b/src/server/game/Calendar/CalendarMgr.cpp index 92f19c0adeb..64116b8f8c1 100644 --- a/src/server/game/Calendar/CalendarMgr.cpp +++ b/src/server/game/Calendar/CalendarMgr.cpp @@ -527,6 +527,10 @@ void CalendarMgr::SendCalendarEventInviteAlert(CalendarEvent const& calendarEven data << uint32(calendarEvent.GetType()); data << int32(calendarEvent.GetDungeonId()); data << uint64(invite.GetInviteId()); + + Guild* guild = sGuildMgr->GetGuildById(calendarEvent.GetGuildId()); + data << uint64(guild ? guild->GetGUID() : 0); + data << uint8(invite.GetStatus()); data << uint8(invite.GetRank()); data.appendPackGUID(calendarEvent.GetCreatorGUID()); @@ -563,7 +567,9 @@ void CalendarMgr::SendCalendarEvent(uint64 guid, CalendarEvent const& calendarEv data << uint32(calendarEvent.GetFlags()); data.AppendPackedTime(calendarEvent.GetEventTime()); data.AppendPackedTime(calendarEvent.GetTimeZoneTime()); - data << uint32(calendarEvent.GetGuildId()); + + Guild* guild = sGuildMgr->GetGuildById(calendarEvent.GetGuildId()); + data << uint64(guild ? guild->GetGUID() : 0); data << uint32(eventInviteeList.size()); for (CalendarInviteStore::const_iterator itr = eventInviteeList.begin(); itr != eventInviteeList.end(); ++itr) diff --git a/src/server/game/Calendar/CalendarMgr.h b/src/server/game/Calendar/CalendarMgr.h index 9bdb7c0a187..cd527a7373e 100644 --- a/src/server/game/Calendar/CalendarMgr.h +++ b/src/server/game/Calendar/CalendarMgr.h @@ -58,7 +58,8 @@ enum CalendarEventType CALENDAR_TYPE_DUNGEON = 1, CALENDAR_TYPE_PVP = 2, CALENDAR_TYPE_MEETING = 3, - CALENDAR_TYPE_OTHER = 4 + CALENDAR_TYPE_OTHER = 4, + CALENDAR_TYPE_HEROIC = 5 }; enum CalendarRepeatType diff --git a/src/server/game/Chat/Channels/ChannelMgr.cpp b/src/server/game/Chat/Channels/ChannelMgr.cpp index 00824ae2056..366b0eee59f 100644 --- a/src/server/game/Chat/Channels/ChannelMgr.cpp +++ b/src/server/game/Chat/Channels/ChannelMgr.cpp @@ -19,6 +19,7 @@ #include "ChannelMgr.h" #include "Player.h" #include "World.h" +#include "WorldSession.h" ChannelMgr::~ChannelMgr() { diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index d77ee5b7f61..0686272f191 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -351,10 +351,9 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, st std::string zoneName = "Unknown"; if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) { - int locale = GetSessionDbcLocale(); - areaName = area->area_name[locale]; + areaName = area->area_name; if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone)) - zoneName = zone->area_name[locale]; + zoneName = zone->area_name; } sLog->outCommand(m_session->GetAccountId(), "Command: %s [Player: %s (Guid: %u) (Account: %u) X: %f Y: %f Z: %f Map: %u (%s) Area: %u (%s) Zone: %s Selected %s: %s (GUID: %u)]", @@ -631,7 +630,8 @@ bool ChatHandler::ShowHelpForCommand(ChatCommand* table, const char* cmd) size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, uint64 senderGUID, uint64 receiverGUID, std::string const& message, uint8 chatTag, std::string const& senderName /*= ""*/, std::string const& receiverName /*= ""*/, - uint32 achievementId /*= 0*/, bool gmMessage /*= false*/, std::string const& channelName /*= ""*/) + uint32 achievementId /*= 0*/, bool gmMessage /*= false*/, std::string const& channelName /*= ""*/, + std::string const& addonPrefix /*= ""*/) { size_t receiverGUIDPos = 0; data.Initialize(!gmMessage ? SMSG_MESSAGECHAT : SMSG_GM_MESSAGECHAT); @@ -658,12 +658,17 @@ size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Languag data << uint32(receiverName.length() + 1); data << receiverName; } + + if (language == LANG_ADDON) + data << addonPrefix; break; case CHAT_MSG_WHISPER_FOREIGN: data << uint32(senderName.length() + 1); data << senderName; receiverGUIDPos = data.wpos(); data << uint64(receiverGUID); + if (language == LANG_ADDON) + data << addonPrefix; break; case CHAT_MSG_BG_SYSTEM_NEUTRAL: case CHAT_MSG_BG_SYSTEM_ALLIANCE: @@ -675,11 +680,16 @@ size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Languag data << uint32(receiverName.length() + 1); data << receiverName; } + + if (language == LANG_ADDON) + data << addonPrefix; break; case CHAT_MSG_ACHIEVEMENT: case CHAT_MSG_GUILD_ACHIEVEMENT: receiverGUIDPos = data.wpos(); data << uint64(receiverGUID); + if (language == LANG_ADDON) + data << addonPrefix; break; default: if (gmMessage) @@ -696,6 +706,9 @@ size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Languag receiverGUIDPos = data.wpos(); data << uint64(receiverGUID); + + if (language == LANG_ADDON) + data << addonPrefix; break; } @@ -705,12 +718,17 @@ size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Languag if (chatType == CHAT_MSG_ACHIEVEMENT || chatType == CHAT_MSG_GUILD_ACHIEVEMENT) data << uint32(achievementId); + else if (chatType == CHAT_MSG_RAID_BOSS_WHISPER || chatType == CHAT_MSG_RAID_BOSS_EMOTE) + { + data << float(0.0f); // Display time in middle of the screen (in seconds), defaults to 10 if not set (cannot be below 1) + data << uint8(0); // Hide in chat frame (only shows in middle of the screen) + } return receiverGUIDPos; } size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, - uint32 achievementId /*= 0*/, std::string const& channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/) + uint32 achievementId /*= 0*/, std::string const& channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/, std::string const& addonPrefix /*= ""*/) { uint64 senderGUID = 0; std::string senderName = ""; @@ -735,7 +753,7 @@ size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Languag receiverName = receiver->GetNameForLocaleIdx(locale); } - return BuildChatPacket(data, chatType, language, senderGUID, receiverGUID, message, chatTag, senderName, receiverName, achievementId, gmMessage, channelName); + return BuildChatPacket(data, chatType, language, senderGUID, receiverGUID, message, chatTag, senderName, receiverName, achievementId, gmMessage, channelName, addonPrefix); } Player* ChatHandler::getSelectedPlayer() diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index a56b79077d7..5c541d07b5a 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -56,10 +56,11 @@ class ChatHandler // Builds chat packet and returns receiver guid position in the packet to substitute in whisper builders static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, uint64 senderGUID, uint64 receiverGUID, std::string const& message, uint8 chatTag, std::string const& senderName = "", std::string const& receiverName = "", - uint32 achievementId = 0, bool gmMessage = false, std::string const& channelName = ""); + uint32 achievementId = 0, bool gmMessage = false, std::string const& channelName = "", + std::string const& addonPrefix = ""); // Builds chat packet and returns receiver guid position in the packet to substitute in whisper builders - static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, uint32 achievementId = 0, std::string const& channelName = "", LocaleConstant locale = DEFAULT_LOCALE); + static size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string const& message, uint32 achievementId = 0, std::string const& channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string const& addonPrefix = ""); static char* LineFromMessage(char*& pos) { char* start = strtok(pos, "\n"); pos = NULL; return start; } diff --git a/src/server/game/Chat/ChatLink.cpp b/src/server/game/Chat/ChatLink.cpp index 12f4b082a9c..3f32447a31f 100644 --- a/src/server/game/Chat/ChatLink.cpp +++ b/src/server/game/Chat/ChatLink.cpp @@ -167,7 +167,7 @@ bool ItemChatLink::Initialize(std::istringstream& iss) return true; } -inline std::string ItemChatLink::FormatName(uint8 index, ItemLocale const* locale, char* const* suffixStrings) const +inline std::string ItemChatLink::FormatName(uint8 index, ItemLocale const* locale, char* suffixStrings) const { std::stringstream ss; if (locale == NULL || index >= locale->Name.size()) @@ -183,7 +183,7 @@ bool ItemChatLink::ValidateName(char* buffer, const char* context) { ChatLink::ValidateName(buffer, context); - char* const* suffixStrings = _suffix ? _suffix->nameSuffix : (_property ? _property->nameSuffix : NULL); + char* suffixStrings = _suffix ? _suffix->nameSuffix : (_property ? _property->nameSuffix : NULL); bool res = (FormatName(LOCALE_enUS, NULL, suffixStrings) == buffer); if (!res) @@ -306,23 +306,18 @@ bool SpellChatLink::ValidateName(char* buffer, const char* context) return false; } - for (uint8 i = 0; i < TOTAL_LOCALES; ++i) + uint32 skillLineNameLength = strlen(skillLine->name); + if (skillLineNameLength > 0 && strncmp(skillLine->name, buffer, skillLineNameLength) == 0) { - uint32 skillLineNameLength = strlen(skillLine->name[i]); - if (skillLineNameLength > 0 && strncmp(skillLine->name[i], buffer, skillLineNameLength) == 0) - { - // found the prefix, remove it to perform spellname validation below - // -2 = strlen(": ") - uint32 spellNameLength = strlen(buffer) - skillLineNameLength - 2; - memmove(buffer, buffer + skillLineNameLength + 2, spellNameLength + 1); - break; - } + // found the prefix, remove it to perform spellname validation below + // -2 = strlen(": ") + uint32 spellNameLength = strlen(buffer) - skillLineNameLength - 2; + memmove(buffer, buffer + skillLineNameLength + 2, spellNameLength + 1); } } - for (uint8 i = 0; i < TOTAL_LOCALES; ++i) - if (*_spell->SpellName[i] && strcmp(_spell->SpellName[i], buffer) == 0) - return true; + if (*_spell->SpellName && strcmp(_spell->SpellName, buffer) == 0) + return true; TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked spell (id: %u) name wasn't found in any localization", context, _spell->Id); return false; @@ -377,9 +372,8 @@ bool AchievementChatLink::ValidateName(char* buffer, const char* context) { ChatLink::ValidateName(buffer, context); - for (uint8 i = 0; i < TOTAL_LOCALES; ++i) - if (*_achievement->name[i] && strcmp(_achievement->name[i], buffer) == 0) - return true; + if (*_achievement->name && strcmp(_achievement->name, buffer) == 0) + return true; TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): linked achievement (id: %u) name wasn't found in any localization", context, _achievement->ID); return false; diff --git a/src/server/game/Chat/ChatLink.h b/src/server/game/Chat/ChatLink.h index 4cfa9c34bf7..ebe2583dc1c 100644 --- a/src/server/game/Chat/ChatLink.h +++ b/src/server/game/Chat/ChatLink.h @@ -65,7 +65,7 @@ public: virtual bool ValidateName(char* buffer, const char* context); protected: - std::string FormatName(uint8 index, ItemLocale const* locale, char* const* suffixStrings) const; + std::string FormatName(uint8 index, ItemLocale const* locale, char* suffixStrings) const; ItemTemplate const* _item; int32 _data[8]; diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 339ec579b1a..edf15aaf1ff 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -75,7 +75,7 @@ bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellIn return false; // not in same map or phase - if (!hatedUnit->IsInMap(hatingUnit) || !hatedUnit->InSamePhase(hatingUnit)) + if (!hatedUnit->IsInMap(hatingUnit) || !hatedUnit->IsInPhase(hatingUnit)) return false; // spell not causing threat @@ -182,7 +182,7 @@ void HostileReference::updateOnlineStatus() && (getTarget()->GetTypeId() != TYPEID_PLAYER || !getTarget()->ToPlayer()->IsGameMaster()) && !getTarget()->HasUnitState(UNIT_STATE_IN_FLIGHT) && getTarget()->IsInMap(GetSourceUnit()) - && getTarget()->InSamePhase(GetSourceUnit()) + && getTarget()->IsInPhase(GetSourceUnit()) ) { Creature* creature = GetSourceUnit()->ToCreature(); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index c77b34a39a3..04ceaefb0d5 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -30,7 +30,7 @@ #include "Spell.h" // Checks if object meets the condition -// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI) +// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: SmartAI) bool Condition::Meets(ConditionSourceInfo& sourceInfo) { ASSERT(ConditionTarget < MAX_CONDITION_TARGETS); @@ -295,9 +295,9 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) condMeets = ConditionValue2 == sWorld->getWorldState(ConditionValue1); break; } - case CONDITION_PHASEMASK: + case CONDITION_PHASEID: { - condMeets = (object->GetPhaseMask() & ConditionValue1) != 0; + condMeets = object->IsInPhase(ConditionValue1); break; } case CONDITION_TITLE: @@ -434,6 +434,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() case TYPEID_CORPSE: mask |= GRID_MAP_TYPE_MASK_CORPSE; break; + case TYPEID_AREATRIGGER: + mask |= GRID_MAP_TYPE_MASK_AREATRIGGER; + break; default: break; } @@ -447,6 +450,8 @@ uint32 Condition::GetSearcherTypeMaskForCondition() mask |= GRID_MAP_TYPE_MASK_GAMEOBJECT; if (ConditionValue1 & TYPEMASK_CORPSE) mask |= GRID_MAP_TYPE_MASK_CORPSE; + if (ConditionValue1 & TYPEMASK_AREATRIGGER) + mask |= GRID_MAP_TYPE_MASK_AREATRIGGER; break; case CONDITION_RELATION_TO: mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; @@ -469,7 +474,7 @@ uint32 Condition::GetSearcherTypeMaskForCondition() case CONDITION_WORLD_STATE: mask |= GRID_MAP_TYPE_MASK_ALL; break; - case CONDITION_PHASEMASK: + case CONDITION_PHASEID: mask |= GRID_MAP_TYPE_MASK_ALL; break; case CONDITION_TITLE: @@ -658,6 +663,7 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || + sourceType == CONDITION_SOURCE_TYPE_PHASE_DEFINITION || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR); } @@ -733,6 +739,22 @@ ConditionList ConditionMgr::GetConditionsForSmartEvent(int32 entryOrGuid, uint32 return cond; } +ConditionList const* ConditionMgr::GetConditionsForPhaseDefinition(uint32 zone, uint32 entry) +{ + PhaseDefinitionConditionContainer::const_iterator itr = PhaseDefinitionsConditionStore.find(zone); + if (itr != PhaseDefinitionsConditionStore.end()) + { + ConditionTypeContainer::const_iterator i = itr->second.find(entry); + if (i != itr->second.end()) + { + TC_LOG_DEBUG("condition", "GetConditionsForPhaseDefinition: found conditions for zone %u entry %u", zone, entry); + return &i->second; + } + } + + return NULL; +} + ConditionList ConditionMgr::GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId) { ConditionList cond; @@ -972,6 +994,13 @@ void ConditionMgr::LoadConditions(bool isReload) ++count; continue; } + case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: + { + PhaseDefinitionsConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); + valid = true; + ++count; + continue; + } case CONDITION_SOURCE_TYPE_NPC_VENDOR: { NpcVendorConditionContainerStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); @@ -1482,6 +1511,13 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) return false; } break; + case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: + /*if (!PhaseMgr::IsConditionTypeSupported(cond->ConditionType)) + { + TC_LOG_ERROR("sql.sql", "Condition source type `CONDITION_SOURCE_TYPE_PHASE_DEFINITION` does not support condition type %u, ignoring.", cond->ConditionType); + return false; + }*/ + break; case CONDITION_SOURCE_TYPE_NPC_VENDOR: { if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) @@ -1497,11 +1533,6 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) } break; } - case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: - { - TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_PHASE_DEFINITION:: is only for 4.3.4 branch, skipped"); - return false; - } case CONDITION_SOURCE_TYPE_GOSSIP_MENU: case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: case CONDITION_SOURCE_TYPE_SMART_EVENT: @@ -1964,12 +1995,17 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) TC_LOG_ERROR("sql.sql", "World state condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } - case CONDITION_PHASEMASK: + case CONDITION_PHASEID: { + if (!sPhaseStore.LookupEntry(cond->ConditionValue1)) + { + TC_LOG_ERROR("sql.sql", "Phase condition has nonexistent phaseid in value1 (%u), skipped", cond->ConditionValue1); + return false; + } if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Phasemask condition has useless data in value2 (%u)!", cond->ConditionValue2); + TC_LOG_ERROR("sql.sql", "Phase condition has useless data in value2 (%u)!", cond->ConditionValue2); if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Phasemask condition has useless data in value3 (%u)!", cond->ConditionValue3); + TC_LOG_ERROR("sql.sql", "Phase condition has useless data in value3 (%u)!", cond->ConditionValue3); break; } case CONDITION_TITLE: @@ -2078,6 +2114,19 @@ void ConditionMgr::Clean() SpellClickEventConditionStore.clear(); + for (PhaseDefinitionConditionContainer::iterator itr = PhaseDefinitionsConditionStore.begin(); itr != PhaseDefinitionsConditionStore.end(); ++itr) + { + for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) + { + for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) + delete *i; + it->second.clear(); + } + itr->second.clear(); + } + + PhaseDefinitionsConditionStore.clear(); + for (NpcVendorConditionContainer::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index d5428ed2d14..9a48985b90d 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -58,7 +58,7 @@ enum ConditionTypes CONDITION_AREAID = 23, // area_id 0 0 true if in area_id CONDITION_CREATURE_TYPE = 24, // cinfo.type 0 0 true if creature_template.type = value1 CONDITION_SPELL = 25, // spell_id 0 0 true if player has learned spell - CONDITION_PHASEMASK = 26, // phasemask 0 0 true if object is in phasemask + CONDITION_PHASEID = 26, // phaseid 0 0 true if object is in phaseid CONDITION_LEVEL = 27, // level ComparisonType 0 true if unit's level is equal to param1 (param2 can modify the statement) CONDITION_QUEST_COMPLETE = 28, // quest_id 0 0 true if player has quest_id with all objectives complete, but not yet rewarded CONDITION_NEAR_CREATURE = 29, // creature entry distance 0 true if there is a creature of entry in range @@ -217,6 +217,7 @@ typedef std::map<ConditionSourceType, ConditionTypeContainer> ConditionContainer typedef std::map<uint32, ConditionTypeContainer> CreatureSpellConditionContainer; typedef std::map<uint32, ConditionTypeContainer> NpcVendorConditionContainer; typedef std::map<std::pair<int32, uint32 /*SAI source_type*/>, ConditionTypeContainer> SmartEventConditionContainer; +typedef std::map<int32 /*zoneId*/, ConditionTypeContainer> PhaseDefinitionConditionContainer; typedef std::map<uint32, ConditionList> ConditionReferenceContainer;//only used for references @@ -248,6 +249,7 @@ class ConditionMgr ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId); ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType); ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId); + ConditionList const* GetConditionsForPhaseDefinition(uint32 zone, uint32 entry); ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId); private: @@ -267,6 +269,7 @@ class ConditionMgr CreatureSpellConditionContainer SpellClickEventConditionStore; NpcVendorConditionContainer NpcVendorConditionContainerStore; SmartEventConditionContainer SmartEventConditionStore; + PhaseDefinitionConditionContainer PhaseDefinitionsConditionStore; }; #define sConditionMgr ConditionMgr::instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp new file mode 100644 index 00000000000..f1436dd90e3 --- /dev/null +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DB2Stores.h" +#include "DB2fmt.h" +#include "DB2Utility.h" +#include "Common.h" +#include "Log.h" +#include "World.h" + +DB2Storage<ItemEntry> sItemStore(Itemfmt, &DB2Utilities::HasItemEntry, &DB2Utilities::WriteItemDbReply); +DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore(ItemCurrencyCostfmt); +DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt); +DB2Storage<ItemSparseEntry> sItemSparseStore(ItemSparsefmt, &DB2Utilities::HasItemSparseEntry, &DB2Utilities::WriteItemSparseDbReply); +DB2Storage<KeyChainEntry> sKeyChainStore(KeyChainfmt); + +typedef std::list<std::string> DB2StoreProblemList; + +typedef std::map<uint32 /*hash*/, DB2StorageBase*> DB2StorageMap; +DB2StorageMap DB2Stores; + +uint32 DB2FilesCount = 0; + +static bool LoadDB2_assert_print(uint32 fsize, uint32 rsize, std::string const& filename) +{ + TC_LOG_ERROR("misc", "Size of '%s' setted by format string (%u) not equal size of C++ structure (%u).", filename.c_str(), fsize, rsize); + + // ASSERT must fail after function call + return false; +} + +template<class T> +inline void LoadDB2(uint32& availableDb2Locales, DB2StoreProblemList& errlist, DB2Storage<T>& storage, std::string const& db2_path, std::string const& filename) +{ + // compatibility format and C++ structure sizes + ASSERT(DB2FileLoader::GetFormatRecordSize(storage.GetFormat()) == sizeof(T) || LoadDB2_assert_print(DB2FileLoader::GetFormatRecordSize(storage.GetFormat()), sizeof(T), filename)); + + ++DB2FilesCount; + + std::string db2_filename = db2_path + filename; + if (storage.Load(db2_filename.c_str(), uint32(sWorld->GetDefaultDbcLocale()))) + { + for (uint32 i = 0; i < TOTAL_LOCALES; ++i) + { + if (!(availableDb2Locales & (1 << i))) + continue; + + if (uint32(sWorld->GetDefaultDbcLocale()) == i) + continue; + + std::string localizedName(db2_path); + localizedName.append(localeNames[i]); + localizedName.push_back('/'); + localizedName.append(filename); + + if (!storage.LoadStringsFrom(localizedName.c_str(), i)) + availableDb2Locales &= ~(1<<i); // mark as not available for speedup next checks + } + } + else + { + // sort problematic db2 to (1) non compatible and (2) nonexistent + if (FILE* f = fopen(db2_filename.c_str(), "rb")) + { + std::ostringstream stream; + stream << db2_filename << " exists, and has " << storage.GetFieldCount() << " field(s) (expected " << strlen(storage.GetFormat()) << "). Extracted file might be from wrong client version."; + std::string buf = stream.str(); + errlist.push_back(buf); + fclose(f); + } + else + errlist.push_back(db2_filename); + } + + DB2Stores[storage.GetHash()] = &storage; +} + +void LoadDB2Stores(std::string const& dataPath) +{ + std::string db2Path = dataPath + "dbc/"; + + DB2StoreProblemList bad_db2_files; + uint32 availableDb2Locales = 0xFF; + + LoadDB2(availableDb2Locales, bad_db2_files, sItemStore, db2Path, "Item.db2"); + LoadDB2(availableDb2Locales, bad_db2_files, sItemCurrencyCostStore, db2Path, "ItemCurrencyCost.db2"); + LoadDB2(availableDb2Locales, bad_db2_files, sItemSparseStore, db2Path, "Item-sparse.db2"); + LoadDB2(availableDb2Locales, bad_db2_files, sItemExtendedCostStore, db2Path, "ItemExtendedCost.db2"); + LoadDB2(availableDb2Locales, bad_db2_files, sKeyChainStore, db2Path, "KeyChain.db2"); + + // error checks + if (bad_db2_files.size() >= DB2FilesCount) + { + TC_LOG_ERROR("misc", "\nIncorrect DataDir value in worldserver.conf or ALL required *.db2 files (%d) not found by path: %sdb2", DB2FilesCount, dataPath.c_str()); + exit(1); + } + else if (!bad_db2_files.empty()) + { + std::string str; + for (std::list<std::string>::iterator i = bad_db2_files.begin(); i != bad_db2_files.end(); ++i) + str += *i + "\n"; + + TC_LOG_ERROR("misc", "\nSome required *.db2 files (%u from %d) not found or not compatible:\n%s", (uint32)bad_db2_files.size(), DB2FilesCount, str.c_str()); + exit(1); + } + + // Check loaded DB2 files proper version + if (!sItemStore.LookupEntry(83086) || // last item added in 4.3.4 (15595) + !sItemExtendedCostStore.LookupEntry(3872) ) // last item extended cost added in 4.3.4 (15595) + { + TC_LOG_ERROR("misc", "Please extract correct db2 files from client 4.3.4 15595."); + exit(1); + } + + TC_LOG_INFO("misc", ">> Initialized %d DB2 data stores.", DB2FilesCount); +} + +DB2StorageBase const* GetDB2Storage(uint32 type) +{ + DB2StorageMap::const_iterator itr = DB2Stores.find(type); + if (itr != DB2Stores.end()) + return itr->second; + + return NULL; +} diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h new file mode 100644 index 00000000000..17a92f98cde --- /dev/null +++ b/src/server/game/DataStores/DB2Stores.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_DB2STORES_H +#define TRINITY_DB2STORES_H + +#include "DB2Store.h" +#include "DB2Structure.h" +#include <string> + +extern DB2Storage<ItemEntry> sItemStore; +extern DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore; +extern DB2Storage<ItemExtendedCostEntry> sItemExtendedCostStore; +extern DB2Storage<ItemSparseEntry> sItemSparseStore; +extern DB2Storage<KeyChainEntry> sKeyChainStore; + +void LoadDB2Stores(std::string const& dataPath); + +DB2StorageBase const* GetDB2Storage(uint32 type); + +#endif diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h new file mode 100644 index 00000000000..0a60d0b860f --- /dev/null +++ b/src/server/game/DataStores/DB2Structure.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_DB2STRUCTURE_H +#define TRINITY_DB2STRUCTURE_H + +#include "Common.h" +#include "ItemPrototype.h" + +// GCC has alternative #pragma pack(N) syntax and old gcc version does not support pack(push, N), also any gcc version does not support it at some platform +#if defined(__GNUC__) +#pragma pack(1) +#else +#pragma pack(push, 1) +#endif + +// Structures used to access raw DB2 data and required packing to portability +struct ItemEntry +{ + uint32 ID; // 0 + uint32 Class; // 1 + uint32 SubClass; // 2 + int32 SoundOverrideSubclass; // 3 + int32 Material; // 4 + uint32 DisplayId; // 5 + uint32 InventoryType; // 6 + uint32 Sheath; // 7 +}; + +struct ItemCurrencyCostEntry +{ + //uint32 Id; + uint32 ItemId; +}; + +struct ItemSparseEntry +{ + uint32 ID; // 0 + uint32 Quality; // 1 + uint32 Flags; // 2 + uint32 Flags2; // 3 + float Unk430_1; + float Unk430_2; + uint32 BuyCount; + uint32 BuyPrice; // 4 + uint32 SellPrice; // 5 + uint32 InventoryType; // 6 + int32 AllowableClass; // 7 + int32 AllowableRace; // 8 + uint32 ItemLevel; // 9 + int32 RequiredLevel; // 10 + uint32 RequiredSkill; // 11 + uint32 RequiredSkillRank; // 12 + uint32 RequiredSpell; // 13 + uint32 RequiredHonorRank; // 14 + uint32 RequiredCityRank; // 15 + uint32 RequiredReputationFaction; // 16 + uint32 RequiredReputationRank; // 17 + uint32 MaxCount; // 18 + uint32 Stackable; // 19 + uint32 ContainerSlots; // 20 + int32 ItemStatType[MAX_ITEM_PROTO_STATS]; // 21 - 30 + uint32 ItemStatValue[MAX_ITEM_PROTO_STATS]; // 31 - 40 + int32 ItemStatUnk1[MAX_ITEM_PROTO_STATS]; // 41 - 50 + int32 ItemStatUnk2[MAX_ITEM_PROTO_STATS]; // 51 - 60 + uint32 ScalingStatDistribution; // 61 + uint32 DamageType; // 62 + uint32 Delay; // 63 + float RangedModRange; // 64 + int32 SpellId[MAX_ITEM_PROTO_SPELLS]; // 65 - 69 + int32 SpellTrigger[MAX_ITEM_PROTO_SPELLS]; // 70 - 74 + int32 SpellCharges[MAX_ITEM_PROTO_SPELLS]; // 75 - 79 + int32 SpellCooldown[MAX_ITEM_PROTO_SPELLS]; // 80 - 84 + int32 SpellCategory[MAX_ITEM_PROTO_SPELLS]; // 85 - 89 + int32 SpellCategoryCooldown[MAX_ITEM_PROTO_SPELLS]; // 90 - 94 + uint32 Bonding; // 95 + LocalizedString* Name; // 96 + LocalizedString* Name2; // 97 + LocalizedString* Name3; // 98 + LocalizedString* Name4; // 99 + LocalizedString* Description; // 100 + uint32 PageText; // 101 + uint32 LanguageID; // 102 + uint32 PageMaterial; // 103 + uint32 StartQuest; // 104 + uint32 LockID; // 105 + int32 Material; // 106 + uint32 Sheath; // 107 + uint32 RandomProperty; // 108 + uint32 RandomSuffix; // 109 + uint32 ItemSet; // 110 + uint32 Area; // 112 + uint32 Map; // 113 + uint32 BagFamily; // 114 + uint32 TotemCategory; // 115 + uint32 Color[MAX_ITEM_PROTO_SOCKETS]; // 116 - 118 + uint32 Content[MAX_ITEM_PROTO_SOCKETS]; // 119 - 121 + int32 SocketBonus; // 122 + uint32 GemProperties; // 123 + float ArmorDamageModifier; // 124 + uint32 Duration; // 125 + uint32 ItemLimitCategory; // 126 + uint32 HolidayId; // 127 + float StatScalingFactor; // 128 + int32 CurrencySubstitutionId; // 129 + int32 CurrencySubstitutionCount; // 130 +}; + +#define MAX_ITEM_EXT_COST_ITEMS 5 +#define MAX_ITEM_EXT_COST_CURRENCIES 5 + +struct ItemExtendedCostEntry +{ + uint32 ID; // 0 extended-cost entry id + //uint32 reqhonorpoints; // 1 required honor points + //uint32 reqarenapoints; // 2 required arena points + uint32 RequiredArenaSlot; // 3 arena slot restrictions (min slot value) + uint32 RequiredItem[MAX_ITEM_EXT_COST_ITEMS]; // 4-8 required item id + uint32 RequiredItemCount[MAX_ITEM_EXT_COST_ITEMS]; // 9-13 required count of 1st item + uint32 RequiredPersonalArenaRating; // 14 required personal arena rating + //uint32 ItemPurchaseGroup; // 15 + uint32 RequiredCurrency[MAX_ITEM_EXT_COST_CURRENCIES];// 16-20 required curency id + uint32 RequiredCurrencyCount[MAX_ITEM_EXT_COST_CURRENCIES];// 21-25 required curency count + uint32 RequiredFactionId; + uint32 RequiredFactionStanding; + uint32 RequirementFlags; + uint32 RequiredGuildLevel; + uint32 RequiredAchievement; +}; + +#define KEYCHAIN_SIZE 32 + +struct KeyChainEntry +{ + uint32 Id; + uint8 Key[KEYCHAIN_SIZE]; +}; + +// GCC has alternative #pragma pack(N) syntax and old gcc version does not support pack(push, N), also any gcc version does not support it at some platform +#if defined(__GNUC__) +#pragma pack() +#else +#pragma pack(pop) +#endif + +#endif
\ No newline at end of file diff --git a/src/server/game/DataStores/DB2Utility.cpp b/src/server/game/DataStores/DB2Utility.cpp new file mode 100644 index 00000000000..5a0174c3a74 --- /dev/null +++ b/src/server/game/DataStores/DB2Utility.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DB2Utility.h" +#include "ObjectMgr.h" + +inline bool ItemExists(uint32 id) +{ + return sObjectMgr->GetItemTemplate(id) != NULL; +} + +bool DB2Utilities::HasItemEntry(DB2Storage<ItemEntry> const& /*store*/, uint32 id) +{ + return ItemExists(id); +} + +bool DB2Utilities::HasItemSparseEntry(DB2Storage<ItemSparseEntry> const& /*store*/, uint32 id) +{ + return ItemExists(id); +} + +void DB2Utilities::WriteItemDbReply(DB2Storage<ItemEntry> const& /*store*/, uint32 id, uint32 /*locale*/, ByteBuffer& buffer) +{ + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id); + ASSERT(proto); + + buffer << uint32(proto->ItemId); + buffer << uint32(proto->Class); + buffer << uint32(proto->SubClass); + buffer << int32(proto->SoundOverrideSubclass); + buffer << uint32(proto->Material); + buffer << uint32(proto->DisplayInfoID); + buffer << uint32(proto->InventoryType); + buffer << uint32(proto->Sheath); +} + +void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*store*/, uint32 id, uint32 locale, ByteBuffer& buffer) +{ + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id); + ASSERT(proto); + + ItemLocale const* localeData = locale ? sObjectMgr->GetItemLocale(id) : NULL; + + buffer << uint32(proto->ItemId); + buffer << uint32(proto->Quality); + buffer << uint32(proto->Flags); + buffer << uint32(proto->Flags2); + buffer << float(proto->Unk430_1); + buffer << float(proto->Unk430_2); + buffer << uint32(proto->BuyCount); + buffer << int32(proto->BuyPrice); + buffer << uint32(proto->SellPrice); + buffer << uint32(proto->InventoryType); + buffer << int32(proto->AllowableClass); + buffer << int32(proto->AllowableRace); + buffer << uint32(proto->ItemLevel); + buffer << uint32(proto->RequiredLevel); + buffer << uint32(proto->RequiredSkill); + buffer << uint32(proto->RequiredSkillRank); + buffer << uint32(proto->RequiredSpell); + buffer << uint32(proto->RequiredHonorRank); + buffer << uint32(proto->RequiredCityRank); + buffer << uint32(proto->RequiredReputationFaction); + buffer << uint32(proto->RequiredReputationRank); + buffer << int32(proto->MaxCount); + buffer << int32(proto->Stackable); + buffer << uint32(proto->ContainerSlots); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x) + buffer << uint32(proto->ItemStat[x].ItemStatType); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x) + buffer << int32(proto->ItemStat[x].ItemStatValue); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x) + buffer << int32(proto->ItemStat[x].ItemStatUnk1); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x) + buffer << int32(proto->ItemStat[x].ItemStatUnk2); + + buffer << uint32(proto->ScalingStatDistribution); + buffer << uint32(proto->DamageType); + buffer << uint32(proto->Delay); + buffer << float(proto->RangedModRange); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) + buffer << int32(proto->Spells[x].SpellId); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) + buffer << uint32(proto->Spells[x].SpellTrigger); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) + buffer << int32(proto->Spells[x].SpellCharges); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) + buffer << int32(proto->Spells[x].SpellCooldown); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) + buffer << uint32(proto->Spells[x].SpellCategory); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x) + buffer << int32(proto->Spells[x].SpellCategoryCooldown); + + buffer << uint32(proto->Bonding); + + // item name + std::string name = proto->Name1; + if (localeData) + ObjectMgr::GetLocaleString(localeData->Name, locale, name); + + buffer << uint16(name.length()); + if (name.length()) + buffer << name; + + for (uint32 i = 0; i < 3; ++i) // other 3 names + buffer << uint16(0); + + std::string desc = proto->Description; + if (localeData) + ObjectMgr::GetLocaleString(localeData->Description, locale, desc); + + buffer << uint16(desc.length()); + if (desc.length()) + buffer << desc; + + buffer << uint32(proto->PageText); + buffer << uint32(proto->LanguageID); + buffer << uint32(proto->PageMaterial); + buffer << uint32(proto->StartQuest); + buffer << uint32(proto->LockID); + buffer << int32(proto->Material); + buffer << uint32(proto->Sheath); + buffer << int32(proto->RandomProperty); + buffer << int32(proto->RandomSuffix); + buffer << uint32(proto->ItemSet); + + buffer << uint32(proto->Area); + buffer << uint32(proto->Map); + buffer << uint32(proto->BagFamily); + buffer << uint32(proto->TotemCategory); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_SOCKETS; ++x) + buffer << uint32(proto->Socket[x].Color); + + for (uint32 x = 0; x < MAX_ITEM_PROTO_SOCKETS; ++x) + buffer << uint32(proto->Socket[x].Content); + + buffer << uint32(proto->socketBonus); + buffer << uint32(proto->GemProperties); + buffer << float(proto->ArmorDamageModifier); + buffer << int32(proto->Duration); + buffer << uint32(proto->ItemLimitCategory); + buffer << uint32(proto->HolidayId); + buffer << float(proto->StatScalingFactor); // StatScalingFactor + buffer << uint32(proto->CurrencySubstitutionId); + buffer << uint32(proto->CurrencySubstitutionCount); +} diff --git a/src/server/game/DataStores/DB2Utility.h b/src/server/game/DataStores/DB2Utility.h new file mode 100644 index 00000000000..f2d58de91ca --- /dev/null +++ b/src/server/game/DataStores/DB2Utility.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DB2PACKETWRITER_H +#define DB2PACKETWRITER_H + +#include "Define.h" + +template<class T> +class DB2Storage; +class ByteBuffer; +struct ItemEntry; +struct ItemSparseEntry; + +namespace DB2Utilities +{ + // + bool HasItemEntry(DB2Storage<ItemEntry> const& store, uint32 id); + bool HasItemSparseEntry(DB2Storage<ItemSparseEntry> const& store, uint32 id); + + // + void WriteItemDbReply(DB2Storage<ItemEntry> const& store, uint32 id, uint32 locale, ByteBuffer& buffer); + void WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& store, uint32 id, uint32 locale, ByteBuffer& buffer); +} + +#endif // DB2PACKETWRITER_H diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h new file mode 100644 index 00000000000..e2904aed51e --- /dev/null +++ b/src/server/game/DataStores/DB2fmt.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_DB2SFRM_H +#define TRINITY_DB2SFRM_H + +char const Itemfmt[]="niiiiiii"; +char const ItemCurrencyCostfmt[]="xn"; +char const ItemSparsefmt[]="niiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiisssssiiiiiiiiiiiiiiiiiiiiiifiiifii"; +char const ItemExtendedCostEntryfmt[]="nxxiiiiiiiiiiiixiiiiiiiiiiiiiii"; +char const KeyChainfmt[]="nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; + +#endif diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 03180b35cb5..2ba5a236f95 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -24,7 +24,7 @@ enum LevelLimit // Client expected level limitation, like as used in DBC item max levels for "until max player level" // use as default max player level, must be fit max level for used client // also see MAX_LEVEL and STRONG_MAX_LEVEL define - DEFAULT_MAX_LEVEL = 80, + DEFAULT_MAX_LEVEL = 85, // client supported max level for player/pets/etc. Avoid overflow or client stability affected. // also see GT_MAX_LEVEL define @@ -63,17 +63,28 @@ enum AchievementFlags { ACHIEVEMENT_FLAG_COUNTER = 0x00000001, // Just count statistic (never stop and complete) ACHIEVEMENT_FLAG_HIDDEN = 0x00000002, // Not sent to client - internal use only - ACHIEVEMENT_FLAG_STORE_MAX_VALUE = 0x00000004, // Store only max value? used only in "Reach level xx" + ACHIEVEMENT_FLAG_PLAY_NO_VISUAL = 0x00000004, // Client does not play achievement earned visual ACHIEVEMENT_FLAG_SUMM = 0x00000008, // Use summ criteria value from all requirements (and calculate max value) ACHIEVEMENT_FLAG_MAX_USED = 0x00000010, // Show max criteria (and calculate max value ??) ACHIEVEMENT_FLAG_REQ_COUNT = 0x00000020, // Use not zero req count (and calculate max value) ACHIEVEMENT_FLAG_AVERAGE = 0x00000040, // Show as average value (value / time_in_days) depend from other flag (by def use last criteria value) ACHIEVEMENT_FLAG_BAR = 0x00000080, // Show as progress bar (value / max vale) depend from other flag (by def use last criteria value) ACHIEVEMENT_FLAG_REALM_FIRST_REACH = 0x00000100, // - ACHIEVEMENT_FLAG_REALM_FIRST_KILL = 0x00000200 // + ACHIEVEMENT_FLAG_REALM_FIRST_KILL = 0x00000200, // + ACHIEVEMENT_FLAG_UNK3 = 0x00000400, // ACHIEVEMENT_FLAG_HIDE_NAME_IN_TIE + ACHIEVEMENT_FLAG_REALM_FIRST_GUILD = 0x00000800, // first guild on realm done something + ACHIEVEMENT_FLAG_SHOW_IN_GUILD_NEWS = 0x00001000, // Shows in guild news + ACHIEVEMENT_FLAG_SHOW_IN_GUILD_HEADER = 0x00002000, // Shows in guild news header + ACHIEVEMENT_FLAG_GUILD = 0x00004000, // + ACHIEVEMENT_FLAG_SHOW_GUILD_MEMBERS = 0x00008000, // + ACHIEVEMENT_FLAG_SHOW_CRITERIA_MEMBERS = 0x00010000 // }; -#define MAX_CRITERIA_REQUIREMENTS 2 +enum AchievementCriteriaLimits +{ + MAX_CRITERIA_REQUIREMENTS = 2, + MAX_ADDITIONAL_CRITERIA_CONDITIONS = 3 +}; enum AchievementCriteriaCondition { @@ -82,11 +93,60 @@ enum AchievementCriteriaCondition ACHIEVEMENT_CRITERIA_CONDITION_UNK2 = 2, // only used in "Complete a daily quest every day for five consecutive days" ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP = 3, // requires you to be on specific map, reset at change ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE = 4, // only used in "Win 10 arenas without losing" + ACHIEVEMENT_CRITERIA_CONDITION_UNK5 = 5, // Have spell? + ACHIEVEMENT_CRITERIA_CONDITION_UNK8 = 8, ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT = 9, // requires the player not to be hit by specific spell ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP = 10, // requires the player not to be in group ACHIEVEMENT_CRITERIA_CONDITION_UNK13 = 13 // unk }; +enum AchievementCriteriaAdditionalCondition +{ + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_DRUNK_VALUE = 1, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_UNK2 = 2, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_LEVEL = 3, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_ENTRY = 4, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_PLAYER = 5, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_DEAD = 6, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_MUST_BE_ENEMY = 7, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_HAS_AURA = 8, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA = 10, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HAS_AURA_TYPE = 11, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_MIN = 14, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_QUALITY_EQUALS = 15, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_UNK16 = 16, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_AREA_OR_ZONE = 17, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_AREA_OR_ZONE = 18, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAP_DIFFICULTY = 20, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_YIELDS_XP = 21, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ARENA_TYPE = 24, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_RACE = 25, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_CLASS = 26, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_RACE = 27, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CLASS = 28, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MAX_GROUP_MEMBERS = 29, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_CREATURE_TYPE = 30, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_MAP = 32, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_CLASS = 33, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_ITEM_SUBCLASS = 34, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_COMPLETE_QUEST_NOT_IN_GROUP = 35, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MIN_PERSONAL_RATING = 37, // NYI (when implementing don't forget about ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE) + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TITLE_BIT_INDEX = 38, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_SOURCE_LEVEL = 39, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_LEVEL = 40, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_ZONE = 41, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_TARGET_HEALTH_PERCENT_BELOW = 46, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_UNK55 = 55, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_MIN_ACHIEVEMENT_POINTS = 56, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_REQUIRES_LFG_GROUP = 58, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_UNK60 = 60, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_REQUIRES_GUILD_GROUP = 61, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GUILD_REPUTATION = 62, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND = 63, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RARITY = 65, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RACE = 66, +}; + enum AchievementCriteriaFlags { ACHIEVEMENT_CRITERIA_FLAG_SHOW_PROGRESS_BAR = 0x00000001, // Show progress as bar @@ -105,6 +165,7 @@ enum AchievementCriteriaTimedTypes ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET = 6, // Timer is started by being target of spell with entry in timerStartEvent ACHIEVEMENT_TIMED_TYPE_CREATURE = 7, // Timer is started by killing creature with entry in timerStartEvent ACHIEVEMENT_TIMED_TYPE_ITEM = 9, // Timer is started by using item with entry in timerStartEvent + ACHIEVEMENT_TIMED_TYPE_UNK = 10, // Unknown ACHIEVEMENT_TIMED_TYPE_MAX }; @@ -113,12 +174,14 @@ enum AchievementCriteriaTypes { ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0, ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS = 3, // struct { uint32 itemCount; } ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5, ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7, ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8, ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9, ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10, // you have to complete a daily quest x times in a row ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11, + ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12, ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13, ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14, ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15, @@ -192,12 +255,6 @@ enum AchievementCriteriaTypes ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM = 91, ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED = 93, ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED = 94, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH = 95, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR = 99, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100, ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT = 101, ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED = 102, ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED = 103, @@ -213,46 +270,56 @@ enum AchievementCriteriaTypes ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS = 114, ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS = 115, ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS = 119, + ACHIEVEMENT_CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS = 124, + ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL = 125, + ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD = 126, + ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL = 127, + ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS = 128, + ACHIEVEMENT_CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS = 129, + ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND = 130, + ACHIEVEMENT_CRITERIA_TYPE_REACH_BG_RATING = 132, + ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD = 133, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD = 134, + ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD = 135, + ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD = 136, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE = 138, //struct { Flag flag; uint32 count; } 1: Guild Dungeon, 2:Guild Challenge, 3:Guild battlefield + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE = 139 //struct { uint32 count; } Guild Challenge }; -#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 120 - -enum AchievementCategory -{ - CATEGORY_CHILDRENS_WEEK = 163 -}; +#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 140 enum AreaFlags { - AREA_FLAG_UNK0 = 0x00000001, // Unknown - AREA_FLAG_UNK1 = 0x00000002, // Razorfen Downs, Naxxramas and Acherus: The Ebon Hold (3.3.5a) - AREA_FLAG_UNK2 = 0x00000004, // Only used for areas on map 571 (development before) - AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // city and city subsones - AREA_FLAG_UNK3 = 0x00000010, // can't find common meaning - AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag? - AREA_FLAG_ALLOW_DUELS = 0x00000040, // allow to duel here - AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas - AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag - AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?) - AREA_FLAG_OUTLAND = 0x00000400, // expansion zones? (only Eye of the Storm not have this flag, but have 0x00004000 flag) - AREA_FLAG_SANCTUARY = 0x00000800, // sanctuary area (PvP disabled) - AREA_FLAG_NEED_FLY = 0x00001000, // Respawn alive at the graveyard without corpse - AREA_FLAG_UNUSED1 = 0x00002000, // Unused in 3.3.5a - AREA_FLAG_OUTLAND2 = 0x00004000, // expansion zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag) - AREA_FLAG_OUTDOOR_PVP = 0x00008000, // pvp objective area? (Death's Door also has this flag although it's no pvp object area) - AREA_FLAG_ARENA_INSTANCE = 0x00010000, // used by instanced arenas only - AREA_FLAG_UNUSED2 = 0x00020000, // Unused in 3.3.5a - AREA_FLAG_CONTESTED_AREA = 0x00040000, // On PvP servers these areas are considered contested, even though the zone it is contained in is a Horde/Alliance territory. - AREA_FLAG_UNK4 = 0x00080000, // Valgarde and Acherus: The Ebon Hold - AREA_FLAG_LOWLEVEL = 0x00100000, // used for some starting areas with area_level <= 15 - AREA_FLAG_TOWN = 0x00200000, // small towns with Inn - AREA_FLAG_REST_ZONE_HORDE = 0x00400000, // Instead of using areatriggers, the zone will act as one for Horde players (Warsong Hold, Acherus: The Ebon Hold, New Agamand Inn, Vengeance Landing Inn, Sunreaver Pavilion, etc) - AREA_FLAG_REST_ZONE_ALLIANCE = 0x00800000, // Instead of using areatriggers, the zone will act as one for Alliance players (Valgarde, Acherus: The Ebon Hold, Westguard Inn, Silver Covenant Pavilion, etc) - AREA_FLAG_WINTERGRASP = 0x01000000, // Wintergrasp and it's subzones - AREA_FLAG_INSIDE = 0x02000000, // used for determinating spell related inside/outside questions in Map::IsOutdoors - AREA_FLAG_OUTSIDE = 0x04000000, // used for determinating spell related inside/outside questions in Map::IsOutdoors - AREA_FLAG_WINTERGRASP_2 = 0x08000000, // Can Hearth And Resurrect From Area - AREA_FLAG_NO_FLY_ZONE = 0x20000000 // Marks zones where you cannot fly + AREA_FLAG_SNOW = 0x00000001, // snow (only Dun Morogh, Naxxramas, Razorfen Downs and Winterspring) + AREA_FLAG_UNK1 = 0x00000002, // Razorfen Downs, Naxxramas and Acherus: The Ebon Hold (3.3.5a) + AREA_FLAG_UNK2 = 0x00000004, // Only used for areas on map 571 (development before) + AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // city and city subsones + AREA_FLAG_UNK3 = 0x00000010, // can't find common meaning + AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag? + AREA_FLAG_ALLOW_DUELS = 0x00000040, // allow to duel here + AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas + AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag + AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?) + AREA_FLAG_OUTLAND = 0x00000400, // expansion zones? (only Eye of the Storm not have this flag, but have 0x00004000 flag) + AREA_FLAG_SANCTUARY = 0x00000800, // sanctuary area (PvP disabled) + AREA_FLAG_NEED_FLY = 0x00001000, // Respawn alive at the graveyard without corpse + AREA_FLAG_UNUSED1 = 0x00002000, // Unused in 3.3.5a + AREA_FLAG_OUTLAND2 = 0x00004000, // expansion zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag) + AREA_FLAG_OUTDOOR_PVP = 0x00008000, // pvp objective area? (Death's Door also has this flag although it's no pvp object area) + AREA_FLAG_ARENA_INSTANCE = 0x00010000, // used by instanced arenas only + AREA_FLAG_UNUSED2 = 0x00020000, // Unused in 3.3.5a + AREA_FLAG_CONTESTED_AREA = 0x00040000, // On PvP servers these areas are considered contested, even though the zone it is contained in is a Horde/Alliance territory. + AREA_FLAG_UNK6 = 0x00080000, // Valgarde and Acherus: The Ebon Hold + AREA_FLAG_LOWLEVEL = 0x00100000, // used for some starting areas with area_level <= 15 + AREA_FLAG_TOWN = 0x00200000, // small towns with Inn + AREA_FLAG_REST_ZONE_HORDE = 0x00400000, // Warsong Hold, Acherus: The Ebon Hold, New Agamand Inn, Vengeance Landing Inn, Sunreaver Pavilion (Something to do with team?) + AREA_FLAG_REST_ZONE_ALLIANCE = 0x00800000, // Valgarde, Acherus: The Ebon Hold, Westguard Inn, Silver Covenant Pavilion (Something to do with team?) + AREA_FLAG_WINTERGRASP = 0x01000000, // Wintergrasp and it's subzones + AREA_FLAG_INSIDE = 0x02000000, // used for determinating spell related inside/outside questions in Map::IsOutdoors + AREA_FLAG_OUTSIDE = 0x04000000, // used for determinating spell related inside/outside questions in Map::IsOutdoors + AREA_FLAG_WINTERGRASP_2 = 0x08000000, // Can Hearth And Resurrect From Area + AREA_FLAG_NO_FLY_ZONE = 0x20000000, // Marks zones where you cannot fly + AREA_FLAG_UNK9 = 0x40000000 }; enum Difficulty @@ -343,12 +410,28 @@ enum ItemEnchantmentType ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET = 8 }; +enum ItemExtendedCostFlags +{ + ITEM_EXT_COST_FLAG_REQUIRE_GUILD = 0x01, + ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1 = 0x02, + ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_2 = 0x04, + ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_3 = 0x08, + ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_4 = 0x10, + ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_5 = 0x20, +}; + enum ItemLimitCategoryMode { ITEM_LIMIT_CATEGORY_MODE_HAVE = 0, // limit applied to amount items in inventory/bank ITEM_LIMIT_CATEGORY_MODE_EQUIP = 1 // limit applied to amount equipped items (including used gems) }; +enum MountFlags +{ + MOUNT_FLAG_CAN_PITCH = 0x4, // client checks MOVEMENTFLAG2_FULL_SPEED_PITCHING + MOUNT_FLAG_CAN_SWIM = 0x8, // client checks MOVEMENTFLAG_SWIMMING +}; + enum SkillRaceClassInfoFlags { SKILL_FLAG_NO_SKILLUP_MESSAGE = 0x2, @@ -362,7 +445,19 @@ enum SkillRaceClassInfoFlags enum SpellCategoryFlags { SPELL_CATEGORY_FLAG_COOLDOWN_SCALES_WITH_WEAPON_SPEED = 0x01, // unused - SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT = 0x04 + SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT = 0x04, + SPELL_CATEGORY_FLAG_COOLDOWN_EXPIRES_AT_MIDNIGHT = 0x08 +}; + +enum TotemCategoryType +{ + TOTEM_CATEGORY_TYPE_KNIFE = 1, + TOTEM_CATEGORY_TYPE_TOTEM = 2, + TOTEM_CATEGORY_TYPE_ROD = 3, + TOTEM_CATEGORY_TYPE_PICK = 21, + TOTEM_CATEGORY_TYPE_STONE = 22, + TOTEM_CATEGORY_TYPE_HAMMER = 23, + TOTEM_CATEGORY_TYPE_SPANNER = 24 }; // SummonProperties.dbc, col 1 @@ -375,6 +470,25 @@ enum SummonPropGroup SUMMON_PROP_GROUP_UNKNOWN3 = 4 // 86 spells in 3.0.3, taxi/mounts }; +// SummonProperties.dbc, col 3 +enum SummonPropType +{ + SUMMON_PROP_TYPE_UNKNOWN = 0, // different summons, 1330 spells in 3.0.3 + SUMMON_PROP_TYPE_SUMMON = 1, // generic summons, 49 spells in 3.0.3 + SUMMON_PROP_TYPE_GUARDIAN = 2, // summon guardian, 393 spells in 3.0.3 + SUMMON_PROP_TYPE_ARMY = 3, // summon army, 5 spells in 3.0.3 + SUMMON_PROP_TYPE_TOTEM = 4, // summon totem, 169 spells in 3.0.3 + SUMMON_PROP_TYPE_CRITTER = 5, // critter/minipet, 195 spells in 3.0.3 + SUMMON_PROP_TYPE_DK = 6, // summon DRW/Ghoul, 2 spells in 3.0.3 + SUMMON_PROP_TYPE_BOMB = 7, // summon bot/bomb, 4 spells in 3.0.3 + SUMMON_PROP_TYPE_PHASING = 8, // something todo with DK prequest line, 2 spells in 3.0.3 + SUMMON_PROP_TYPE_SIEGE_VEH = 9, // summon different vehicles, 14 spells in 3.0.3 + SUMMON_PROP_TYPE_DRAKE_VEH = 10, // summon drake (vehicle), 3 spells + SUMMON_PROP_TYPE_LIGHTWELL = 11, // summon lightwell, 6 spells in 3.0.3 + SUMMON_PROP_TYPE_JEEVES = 12, // summon Jeeves, 1 spell in 3.3.5a + SUMMON_PROP_TYPE_LASHTAIL = 13 // Lashtail Hatchling, 1 spell in 4.2.2 +}; + // SummonProperties.dbc, col 5 enum SummonPropFlags { @@ -394,18 +508,12 @@ enum SummonPropFlags SUMMON_PROP_FLAG_UNK13 = 0x00001000, // Lightwell, Jeeves, Gnomish Alarm-o-bot, Build vehicles(wintergrasp) SUMMON_PROP_FLAG_UNK14 = 0x00002000, // Guides, player follows SUMMON_PROP_FLAG_UNK15 = 0x00004000, // Force of Nature, Shadowfiend, Feral Spirit, Summon Water Elemental - SUMMON_PROP_FLAG_UNK16 = 0x00008000 // Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase related? -}; - -enum TotemCategoryType -{ - TOTEM_CATEGORY_TYPE_KNIFE = 1, - TOTEM_CATEGORY_TYPE_TOTEM = 2, - TOTEM_CATEGORY_TYPE_ROD = 3, - TOTEM_CATEGORY_TYPE_PICK = 21, - TOTEM_CATEGORY_TYPE_STONE = 22, - TOTEM_CATEGORY_TYPE_HAMMER = 23, - TOTEM_CATEGORY_TYPE_SPANNER = 24 + SUMMON_PROP_FLAG_UNK16 = 0x00008000, // Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase related? + SUMMON_PROP_FLAG_UNK17 = 0x00010000, + SUMMON_PROP_FLAG_UNK18 = 0x00020000, + SUMMON_PROP_FLAG_UNK19 = 0x00040000, + SUMMON_PROP_FLAG_UNK20 = 0x00080000, + SUMMON_PROP_FLAG_UNK21 = 0x00100000 // Totems }; enum VehicleSeatFlags @@ -458,4 +566,15 @@ enum VehicleSeatFlagsB VEHICLE_SEAT_FLAG_B_VEHICLE_PLAYERFRAME_UI = 0x80000000 // Lua_UnitHasVehiclePlayerFrameUI - actually checked for flagsb &~ 0x80000000 }; +// CurrencyTypes.dbc +enum CurrencyTypes +{ + CURRENCY_TYPE_CONQUEST_POINTS = 390, + CURRENCY_TYPE_HONOR_POINTS = 392, + CURRENCY_TYPE_JUSTICE_POINTS = 395, + CURRENCY_TYPE_VALOR_POINTS = 396, + CURRENCY_TYPE_CONQUEST_META_ARENA = 483, + CURRENCY_TYPE_CONQUEST_META_RBG = 484, +}; + #endif diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index e960422cbbc..05a1eb71e90 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -22,6 +22,7 @@ #include "SpellMgr.h" #include "TransportMgr.h" #include "DBCfmt.h" +#include "ItemPrototype.h" #include "Timer.h" #include "ObjectDefines.h" @@ -60,6 +61,7 @@ static WMOAreaInfoByTripple sWMOAreaInfoByTripple; DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt); DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt); DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt); +DBCStorage <ArmorLocationEntry> sArmorLocationStore(ArmorLocationfmt); DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt); DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEntryfmt); DBCStorage <BannedAddOnsEntry> sBannedAddOnsStore(BannedAddOnsfmt); @@ -71,6 +73,7 @@ DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt); DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt); DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt); DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt); +DBCStorage <ChrPowerTypesEntry> sChrPowerTypesStore(ChrClassesXPowerTypesfmt); DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt); DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt); DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt); @@ -79,6 +82,7 @@ DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore(CreatureModelDatafmt DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt); DBCStorage <CreatureTypeEntry> sCreatureTypeStore(CreatureTypefmt); DBCStorage <CurrencyTypesEntry> sCurrencyTypesStore(CurrencyTypesfmt); +uint32 PowersByClass[MAX_CLASSES][MAX_POWERS]; DBCStorage <DestructibleModelDataEntry> sDestructibleModelDataStore(DestructibleModelDatafmt); DBCStorage <DungeonEncounterEntry> sDungeonEncounterStore(DungeonEncounterfmt); @@ -108,16 +112,36 @@ DBCStorage <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore(GtNPCManaCos DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore(GtOCTClassCombatRatingScalarfmt); DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore(GtOCTRegenHPfmt); //DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore(GtOCTRegenMPfmt); -- not used currently -DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore(GtRegenHPPerSptfmt); +DBCStorage <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore(GtOCTHpPerStaminafmt); DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptfmt); +DBCStorage <GtSpellScalingEntry> sGtSpellScalingStore(GtSpellScalingfmt); +DBCStorage <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore(GtOCTBaseHPByClassfmt); +DBCStorage <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore(GtOCTBaseMPByClassfmt); +DBCStorage <GuildPerkSpellsEntry> sGuildPerkSpellsStore(GuildPerkSpellsfmt); DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt); -DBCStorage <ItemEntry> sItemStore(Itemfmt); +DBCStorage <ImportPriceArmorEntry> sImportPriceArmorStore(ImportPriceArmorfmt); +DBCStorage <ImportPriceQualityEntry> sImportPriceQualityStore(ImportPriceQualityfmt); +DBCStorage <ImportPriceShieldEntry> sImportPriceShieldStore(ImportPriceShieldfmt); +DBCStorage <ImportPriceWeaponEntry> sImportPriceWeaponStore(ImportPriceWeaponfmt); +DBCStorage <ItemPriceBaseEntry> sItemPriceBaseStore(ItemPriceBasefmt); +DBCStorage <ItemReforgeEntry> sItemReforgeStore(ItemReforgefmt); +DBCStorage <ItemArmorQualityEntry> sItemArmorQualityStore(ItemArmorQualityfmt); +DBCStorage <ItemArmorShieldEntry> sItemArmorShieldStore(ItemArmorShieldfmt); +DBCStorage <ItemArmorTotalEntry> sItemArmorTotalStore(ItemArmorTotalfmt); +DBCStorage <ItemClassEntry> sItemClassStore(ItemClassfmt); DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt); -//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt); +DBCStorage <ItemDamageEntry> sItemDamageAmmoStore(ItemDamagefmt); +DBCStorage <ItemDamageEntry> sItemDamageOneHandStore(ItemDamagefmt); +DBCStorage <ItemDamageEntry> sItemDamageOneHandCasterStore(ItemDamagefmt); +DBCStorage <ItemDamageEntry> sItemDamageRangedStore(ItemDamagefmt); +DBCStorage <ItemDamageEntry> sItemDamageThrownStore(ItemDamagefmt); +DBCStorage <ItemDamageEntry> sItemDamageTwoHandStore(ItemDamagefmt); +DBCStorage <ItemDamageEntry> sItemDamageTwoHandCasterStore(ItemDamagefmt); +DBCStorage <ItemDamageEntry> sItemDamageWandStore(ItemDamagefmt); +DBCStorage <ItemDisenchantLootEntry> sItemDisenchantLootStore(ItemDisenchantLootfmt); //DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently -DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt); DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore(ItemLimitCategoryEntryfmt); DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt); DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt); @@ -136,6 +160,12 @@ DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // o MapDifficultyMap sMapDifficultyMap; DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt); +DBCStorage <MountCapabilityEntry> sMountCapabilityStore(MountCapabilityfmt); +DBCStorage <MountTypeEntry> sMountTypeStore(MountTypefmt); + +DBCStorage <NameGenEntry> sNameGenStore(NameGenfmt); +NameGenVectorArraysMap sGenNameVectoArraysMap; +DBCStorage <NumTalentsAtLevelEntry> sNumTalentsAtLevelStore(NumTalentsAtLevelfmt); DBCStorage <OverrideSpellDataEntry> sOverrideSpellDataStore(OverrideSpellDatafmt); @@ -163,20 +193,40 @@ DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt); SpellCategoryStore sSpellsByCategoryStore; PetFamilySpellsStore sPetFamilySpellsStore; + +DBCStorage <SpellReagentsEntry> sSpellReagentsStore(SpellReagentsEntryfmt); +DBCStorage <SpellScalingEntry> sSpellScalingStore(SpellScalingEntryfmt); +DBCStorage <SpellTotemsEntry> sSpellTotemsStore(SpellTotemsEntryfmt); +DBCStorage <SpellTargetRestrictionsEntry> sSpellTargetRestrictionsStore(SpellTargetRestrictionsEntryfmt); +DBCStorage <SpellPowerEntry> sSpellPowerStore(SpellPowerEntryfmt); +DBCStorage <SpellLevelsEntry> sSpellLevelsStore(SpellLevelsEntryfmt); +DBCStorage <SpellInterruptsEntry> sSpellInterruptsStore(SpellInterruptsEntryfmt); +DBCStorage <SpellEquippedItemsEntry> sSpellEquippedItemsStore(SpellEquippedItemsEntryfmt); +DBCStorage <SpellClassOptionsEntry> sSpellClassOptionsStore(SpellClassOptionsEntryfmt); +DBCStorage <SpellCooldownsEntry> sSpellCooldownsStore(SpellCooldownsEntryfmt); +DBCStorage <SpellAuraOptionsEntry> sSpellAuraOptionsStore(SpellAuraOptionsEntryfmt); +DBCStorage <SpellAuraRestrictionsEntry> sSpellAuraRestrictionsStore(SpellAuraRestrictionsEntryfmt); +DBCStorage <SpellCastingRequirementsEntry> sSpellCastingRequirementsStore(SpellCastingRequirementsEntryfmt); DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore(SpellCastTimefmt); +DBCStorage <SpellCategoriesEntry> sSpellCategoriesStore(SpellCategoriesEntryfmt); DBCStorage <SpellCategoryEntry> sSpellCategoryStore(SpellCategoryfmt); +DBCStorage <SpellEffectEntry> sSpellEffectStore(SpellEffectEntryfmt); DBCStorage <SpellDifficultyEntry> sSpellDifficultyStore(SpellDifficultyfmt); DBCStorage <SpellDurationEntry> sSpellDurationStore(SpellDurationfmt); DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore(SpellFocusObjectfmt); DBCStorage <SpellRadiusEntry> sSpellRadiusStore(SpellRadiusfmt); DBCStorage <SpellRangeEntry> sSpellRangeStore(SpellRangefmt); DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore(SpellRuneCostfmt); -DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftfmt); +DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore(SpellShapeshiftEntryfmt); +DBCStorage <SpellShapeshiftFormEntry> sSpellShapeshiftFormStore(SpellShapeshiftFormfmt); DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt); DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt); DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt); TalentSpellPosMap sTalentSpellPosMap; DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt); +DBCStorage <TalentTreePrimarySpellsEntry> sTalentTreePrimarySpellsStore(TalentTreePrimarySpellsfmt); +typedef std::map<uint32, std::vector<uint32> > TalentTreePrimarySpellsMap; +TalentTreePrimarySpellsMap sTalentTreePrimarySpellsMap; // store absolute bit position for first rank for talent inspect static uint32 sTalentTabPages[MAX_CLASSES][3]; @@ -196,16 +246,20 @@ DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt); TaxiPathNodesByPath sTaxiPathNodesByPath; static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt); -DBCStorage <TeamContributionPointsEntry> sTeamContributionPointsStore(TeamContributionPointsfmt); DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt); DBCStorage <TransportAnimationEntry> sTransportAnimationStore(TransportAnimationfmt); DBCStorage <TransportRotationEntry> sTransportRotationStore(TransportRotationfmt); +DBCStorage <UnitPowerBarEntry> sUnitPowerBarStore(UnitPowerBarfmt); DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt); DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt); DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore(WMOAreaTableEntryfmt); DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt); DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt); DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt); +DBCStorage <PhaseEntry> sPhaseStore(PhaseEntryfmt); +DBCStorage <PhaseGroupEntry> sPhaseGroupStore(PhaseGroupfmt); + +PhaseGroupContainer sPhasesByGroup; typedef std::list<std::string> StoreProblemList; @@ -290,40 +344,59 @@ void LoadDBCStores(const std::string& dataPath) } } - LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex); - LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sAreaGroupStore, dbcPath, "AreaGroup.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sAreaPOIStore, dbcPath, "AreaPOI.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sAuctionHouseStore, dbcPath, "AuctionHouse.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sBankBagSlotPricesStore, dbcPath, "BankBagSlotPrices.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex);//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sAreaGroupStore, dbcPath, "AreaGroup.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sAreaPOIStore, dbcPath, "AreaPOI.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sAuctionHouseStore, dbcPath, "AuctionHouse.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sArmorLocationStore, dbcPath, "ArmorLocation.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sBankBagSlotPricesStore, dbcPath, "BankBagSlotPrices.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sBannedAddOnsStore, dbcPath, "BannedAddOns.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sBattlemasterListStore, dbcPath, "BattlemasterList.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sBarberShopStyleStore, dbcPath, "BarberShopStyle.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCharStartOutfitStore, dbcPath, "CharStartOutfit.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sBattlemasterListStore, dbcPath, "BattlemasterList.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sBarberShopStyleStore, dbcPath, "BarberShopStyle.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sCharStartOutfitStore, dbcPath, "CharStartOutfit.dbc");//15595 for (uint32 i = 0; i < sCharStartOutfitStore.GetNumRows(); ++i) if (CharStartOutfitEntry const* outfit = sCharStartOutfitStore.LookupEntry(i)) sCharStartOutfitMap[outfit->Race | (outfit->Class << 8) | (outfit->Gender << 16)] = outfit; - LoadDBC(availableDbcLocales, bad_dbc_files, sCharTitlesStore, dbcPath, "CharTitles.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sChatChannelsStore, dbcPath, "ChatChannels.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sChrClassesStore, dbcPath, "ChrClasses.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sChrRacesStore, dbcPath, "ChrRaces.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCinematicSequencesStore, dbcPath, "CinematicSequences.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoStore, dbcPath, "CreatureDisplayInfo.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoExtraStore, dbcPath, "CreatureDisplayInfoExtra.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureFamilyStore, dbcPath, "CreatureFamily.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureModelDataStore, dbcPath, "CreatureModelData.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureSpellDataStore, dbcPath, "CreatureSpellData.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureTypeStore, dbcPath, "CreatureType.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sCurrencyTypesStore, dbcPath, "CurrencyTypes.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sDestructibleModelDataStore, dbcPath, "DestructibleModelData.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sDungeonEncounterStore, dbcPath, "DungeonEncounter.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sDurabilityCostsStore, dbcPath, "DurabilityCosts.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sDurabilityQualityStore, dbcPath, "DurabilityQuality.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sEmotesStore, dbcPath, "Emotes.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sEmotesTextStore, dbcPath, "EmotesText.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sFactionStore, dbcPath, "Faction.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sCharTitlesStore, dbcPath, "CharTitles.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sChatChannelsStore, dbcPath, "ChatChannels.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sChrClassesStore, dbcPath, "ChrClasses.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sChrRacesStore, dbcPath, "ChrRaces.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sChrPowerTypesStore, dbcPath, "ChrClassesXPowerTypes.dbc");//15595 + for (uint32 i = 0; i < MAX_CLASSES; ++i) + for (uint32 j = 0; j < MAX_POWERS; ++j) + PowersByClass[i][j] = MAX_POWERS; + + for (uint32 i = 0; i < sChrPowerTypesStore.GetNumRows(); ++i) + { + if (ChrPowerTypesEntry const* power = sChrPowerTypesStore.LookupEntry(i)) + { + uint32 index = 0; + for (uint32 j = 0; j < MAX_POWERS; ++j) + if (PowersByClass[power->classId][j] != MAX_POWERS) + ++index; + + PowersByClass[power->classId][power->power] = index; + } + } + + LoadDBC(availableDbcLocales, bad_dbc_files, sCinematicSequencesStore, dbcPath, "CinematicSequences.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoStore, dbcPath, "CreatureDisplayInfo.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoExtraStore, dbcPath, "CreatureDisplayInfoExtra.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureFamilyStore, dbcPath, "CreatureFamily.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureModelDataStore, dbcPath, "CreatureModelData.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureSpellDataStore, dbcPath, "CreatureSpellData.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureTypeStore, dbcPath, "CreatureType.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sCurrencyTypesStore, dbcPath, "CurrencyTypes.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sDestructibleModelDataStore, dbcPath, "DestructibleModelData.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sDungeonEncounterStore, dbcPath, "DungeonEncounter.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sDurabilityCostsStore, dbcPath, "DurabilityCosts.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sDurabilityQualityStore, dbcPath, "DurabilityQuality.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sEmotesStore, dbcPath, "Emotes.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sEmotesTextStore, dbcPath, "EmotesText.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sFactionStore, dbcPath, "Faction.dbc");//15595 for (uint32 i=0; i<sFactionStore.GetNumRows(); ++i) { FactionEntry const* faction = sFactionStore.LookupEntry(i); @@ -334,8 +407,8 @@ void LoadDBCStores(const std::string& dataPath) } } - LoadDBC(availableDbcLocales, bad_dbc_files, sFactionTemplateStore, dbcPath, "FactionTemplate.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGameObjectDisplayInfoStore, dbcPath, "GameObjectDisplayInfo.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sFactionTemplateStore, dbcPath, "FactionTemplate.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGameObjectDisplayInfoStore, dbcPath, "GameObjectDisplayInfo.dbc");//15595 for (uint32 i = 0; i < sGameObjectDisplayInfoStore.GetNumRows(); ++i) { if (GameObjectDisplayInfoEntry const* info = sGameObjectDisplayInfoStore.LookupEntry(i)) @@ -349,69 +422,110 @@ void LoadDBCStores(const std::string& dataPath) } } - LoadDBC(availableDbcLocales, bad_dbc_files, sGemPropertiesStore, dbcPath, "GemProperties.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGlyphPropertiesStore, dbcPath, "GlyphProperties.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGlyphSlotStore, dbcPath, "GlyphSlot.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtBarberShopCostBaseStore, dbcPath, "gtBarberShopCostBase.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtCombatRatingsStore, dbcPath, "gtCombatRatings.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToMeleeCritBaseStore, dbcPath, "gtChanceToMeleeCritBase.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToMeleeCritStore, dbcPath, "gtChanceToMeleeCrit.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToSpellCritBaseStore, dbcPath, "gtChanceToSpellCritBase.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToSpellCritStore, dbcPath, "gtChanceToSpellCrit.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sGemPropertiesStore, dbcPath, "GemProperties.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGlyphPropertiesStore, dbcPath, "GlyphProperties.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGlyphSlotStore, dbcPath, "GlyphSlot.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtBarberShopCostBaseStore, dbcPath, "gtBarberShopCostBase.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtCombatRatingsStore, dbcPath, "gtCombatRatings.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToMeleeCritBaseStore, dbcPath, "gtChanceToMeleeCritBase.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToMeleeCritStore, dbcPath, "gtChanceToMeleeCrit.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToSpellCritBaseStore, dbcPath, "gtChanceToSpellCritBase.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtChanceToSpellCritStore, dbcPath, "gtChanceToSpellCrit.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sGtNPCManaCostScalerStore, dbcPath, "gtNPCManaCostScaler.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTClassCombatRatingScalarStore, dbcPath, "gtOCTClassCombatRatingScalar.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTRegenHPStore, dbcPath, "gtOCTRegenHP.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTClassCombatRatingScalarStore, dbcPath, "gtOCTClassCombatRatingScalar.dbc");//15595 + //LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTRegenHPStore, dbcPath, "gtOCTRegenHP.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTHpPerStaminaStore, dbcPath, "gtOCTHpPerStamina.dbc");//15595 //LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sGtOCTRegenMPStore, dbcPath, "gtOCTRegenMP.dbc"); -- not used currently - LoadDBC(availableDbcLocales, bad_dbc_files, sGtRegenHPPerSptStore, dbcPath, "gtRegenHPPerSpt.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sGtRegenMPPerSptStore, dbcPath, "gtRegenMPPerSpt.dbc"); - - LoadDBC(availableDbcLocales, bad_dbc_files, sHolidaysStore, dbcPath, "Holidays.dbc"); - - LoadDBC(availableDbcLocales, bad_dbc_files, sItemStore, dbcPath, "Item.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sItemBagFamilyStore, dbcPath, "ItemBagFamily.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sGtRegenMPPerSptStore, dbcPath, "gtRegenMPPerSpt.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtSpellScalingStore, dbcPath, "gtSpellScaling.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTBaseHPByClassStore, dbcPath, "gtOCTBaseHPByClass.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGtOCTBaseMPByClassStore, dbcPath, "gtOCTBaseMPByClass.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sGuildPerkSpellsStore, dbcPath, "GuildPerkSpells.dbc");//15595 + + LoadDBC(availableDbcLocales, bad_dbc_files, sHolidaysStore, dbcPath, "Holidays.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sImportPriceArmorStore, dbcPath, "ImportPriceArmor.dbc"); // 15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sImportPriceQualityStore, dbcPath, "ImportPriceQuality.dbc"); // 15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sImportPriceShieldStore, dbcPath, "ImportPriceShield.dbc"); // 15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sImportPriceWeaponStore, dbcPath, "ImportPriceWeapon.dbc"); // 15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemPriceBaseStore, dbcPath, "ItemPriceBase.dbc"); // 15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemReforgeStore, dbcPath, "ItemReforge.dbc"); // 15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemBagFamilyStore, dbcPath, "ItemBagFamily.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemClassStore, dbcPath, "ItemClass.dbc"); // 15595 //LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sItemDisplayInfoStore, dbcPath, "ItemDisplayInfo.dbc"); -- not used currently - //LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sItemCondExtCostsStore, dbcPath, "ItemCondExtCosts.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sItemExtendedCostStore, dbcPath, "ItemExtendedCost.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sItemLimitCategoryStore, dbcPath, "ItemLimitCategory.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sItemRandomPropertiesStore, dbcPath, "ItemRandomProperties.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sItemRandomSuffixStore, dbcPath, "ItemRandomSuffix.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sItemSetStore, dbcPath, "ItemSet.dbc"); - - LoadDBC(availableDbcLocales, bad_dbc_files, sLFGDungeonStore, dbcPath, "LFGDungeons.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sLightStore, dbcPath, "Light.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sLiquidTypeStore, dbcPath, "LiquidType.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sLockStore, dbcPath, "Lock.dbc"); - - LoadDBC(availableDbcLocales, bad_dbc_files, sMailTemplateStore, dbcPath, "MailTemplate.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sMapStore, dbcPath, "Map.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sMapDifficultyStore, dbcPath, "MapDifficulty.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sItemLimitCategoryStore, dbcPath, "ItemLimitCategory.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemRandomPropertiesStore, dbcPath, "ItemRandomProperties.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemRandomSuffixStore, dbcPath, "ItemRandomSuffix.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemSetStore, dbcPath, "ItemSet.dbc");//15595 + + LoadDBC(availableDbcLocales, bad_dbc_files, sItemArmorQualityStore, dbcPath, "ItemArmorQuality.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemArmorShieldStore, dbcPath, "ItemArmorShield.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemArmorTotalStore, dbcPath, "ItemArmorTotal.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDamageAmmoStore, dbcPath, "ItemDamageAmmo.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDamageOneHandStore, dbcPath, "ItemDamageOneHand.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDamageOneHandCasterStore, dbcPath, "ItemDamageOneHandCaster.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDamageRangedStore, dbcPath, "ItemDamageRanged.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDamageThrownStore, dbcPath, "ItemDamageThrown.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDamageTwoHandStore, dbcPath, "ItemDamageTwoHand.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDamageTwoHandCasterStore, dbcPath, "ItemDamageTwoHandCaster.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDamageWandStore, dbcPath, "ItemDamageWand.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sItemDisenchantLootStore, dbcPath, "ItemDisenchantLoot.dbc"); + + LoadDBC(availableDbcLocales, bad_dbc_files, sLFGDungeonStore, dbcPath, "LFGDungeons.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sLightStore, dbcPath, "Light.dbc"); //15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sLiquidTypeStore, dbcPath, "LiquidType.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sLockStore, dbcPath, "Lock.dbc");//15595 + + LoadDBC(availableDbcLocales, bad_dbc_files, sMailTemplateStore, dbcPath, "MailTemplate.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sMapStore, dbcPath, "Map.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sMapDifficultyStore, dbcPath, "MapDifficulty.dbc");//15595 // fill data - for (uint32 i = 1; i < sMapDifficultyStore.GetNumRows(); ++i) + sMapDifficultyMap[MAKE_PAIR32(0, 0)] = MapDifficulty(0, 0, false);//map 0 is missingg from MapDifficulty.dbc use this till its ported to sql + for (uint32 i = 0; i < sMapDifficultyStore.GetNumRows(); ++i) if (MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i)) - sMapDifficultyMap[MAKE_PAIR32(entry->MapId, entry->Difficulty)] = MapDifficulty(entry->resetTime, entry->maxPlayers, entry->areaTriggerText[0] != '\0'); + sMapDifficultyMap[MAKE_PAIR32(entry->MapId, entry->Difficulty)] = MapDifficulty(entry->resetTime, entry->maxPlayers, entry->areaTriggerText[0] > 0); sMapDifficultyStore.Clear(); - LoadDBC(availableDbcLocales, bad_dbc_files, sMovieStore, dbcPath, "Movie.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sMountCapabilityStore, dbcPath, "MountCapability.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sMountTypeStore, dbcPath, "MountType.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sOverrideSpellDataStore, dbcPath, "OverrideSpellData.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sNameGenStore, dbcPath, "NameGen.dbc");//15595 + for (uint32 i = 0; i < sNameGenStore.GetNumRows(); ++i) + if (NameGenEntry const* entry = sNameGenStore.LookupEntry(i)) + sGenNameVectoArraysMap[entry->race].stringVectorArray[entry->gender].push_back(std::string(entry->name)); + sNameGenStore.Clear(); + LoadDBC(availableDbcLocales, bad_dbc_files, sNumTalentsAtLevelStore, dbcPath, "NumTalentsAtLevel.dbc");//15595 + + LoadDBC(availableDbcLocales, bad_dbc_files, sMovieStore, dbcPath, "Movie.dbc");//15595 + + LoadDBC(availableDbcLocales, bad_dbc_files, sOverrideSpellDataStore, dbcPath, "OverrideSpellData.dbc");//15595 + + LoadDBC(availableDbcLocales, bad_dbc_files, sPhaseStore, dbcPath, "Phase.dbc"); // 15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sPhaseGroupStore, dbcPath, "PhaseXPhaseGroup.dbc"); // 15595 + + for (uint32 i = 0; i < sPhaseGroupStore.GetNumRows(); ++i) + if (PhaseGroupEntry const* group = sPhaseGroupStore.LookupEntry(i)) + if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseId)) + sPhasesByGroup[group->GroupId].insert(phase->ID); LoadDBC(availableDbcLocales, bad_dbc_files, sPowerDisplayStore, dbcPath, "PowerDisplay.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sPvPDifficultyStore, dbcPath, "PvpDifficulty.dbc"); + + LoadDBC(availableDbcLocales, bad_dbc_files, sPvPDifficultyStore, dbcPath, "PvpDifficulty.dbc");//15595 + for (uint32 i = 0; i < sPvPDifficultyStore.GetNumRows(); ++i) if (PvPDifficultyEntry const* entry = sPvPDifficultyStore.LookupEntry(i)) if (entry->bracketId > MAX_BATTLEGROUND_BRACKETS) ASSERT(false && "Need update MAX_BATTLEGROUND_BRACKETS by DBC data"); - LoadDBC(availableDbcLocales, bad_dbc_files, sQuestXPStore, dbcPath, "QuestXP.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sQuestFactionRewardStore, dbcPath, "QuestFactionReward.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sQuestSortStore, dbcPath, "QuestSort.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sQuestXPStore, dbcPath, "QuestXP.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sQuestFactionRewardStore, dbcPath, "QuestFactionReward.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sQuestSortStore, dbcPath, "QuestSort.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sRandomPropertiesPointsStore, dbcPath, "RandPropPoints.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sRandomPropertiesPointsStore, dbcPath, "RandPropPoints.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatDistributionStore, dbcPath, "ScalingStatDistribution.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatValuesStore, dbcPath, "ScalingStatValues.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineStore, dbcPath, "SkillLine.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineAbilityStore, dbcPath, "SkillLineAbility.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatDistributionStore, dbcPath, "ScalingStatDistribution.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatValuesStore, dbcPath, "ScalingStatValues.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineStore, dbcPath, "SkillLine.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSkillLineAbilityStore, dbcPath, "SkillLineAbility.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sSkillRaceClassInfoStore, dbcPath, "SkillRaceClassInfo.dbc"); for (uint32 i = 0; i < sSkillRaceClassInfoStore.GetNumRows(); ++i) if (SkillRaceClassInfoEntry const* entry = sSkillRaceClassInfoStore.LookupEntry(i)) @@ -419,23 +533,62 @@ void LoadDBCStores(const std::string& dataPath) SkillRaceClassInfoBySkill.emplace(entry->SkillId, entry); LoadDBC(availableDbcLocales, bad_dbc_files, sSkillTiersStore, dbcPath, "SkillTiers.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc", &CustomSpellEntryfmt, &CustomSpellEntryIndex); + LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc", &CustomSpellEntryfmt, &CustomSpellEntryIndex);// + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoriesStore, dbcPath,"SpellCategories.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoryStore, dbcPath, "SpellCategory.dbc"); for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) { SpellEntry const* spell = sSpellStore.LookupEntry(i); - if (spell && spell->Category) - sSpellsByCategoryStore[spell->Category].insert(i); + if (!spell) + continue; + + if (SpellCategoriesEntry const* category = sSpellCategoriesStore.LookupEntry(spell->SpellCategoriesId)) + sSpellsByCategoryStore[category->Category].insert(i); } + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellReagentsStore, dbcPath,"SpellReagents.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellScalingStore, dbcPath,"SpellScaling.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellTotemsStore, dbcPath,"SpellTotems.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellTargetRestrictionsStore, dbcPath,"SpellTargetRestrictions.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellPowerStore, dbcPath,"SpellPower.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellLevelsStore, dbcPath,"SpellLevels.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellInterruptsStore, dbcPath,"SpellInterrupts.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellEquippedItemsStore, dbcPath,"SpellEquippedItems.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellClassOptionsStore, dbcPath,"SpellClassOptions.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCooldownsStore, dbcPath,"SpellCooldowns.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellAuraOptionsStore, dbcPath,"SpellAuraOptions.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellAuraRestrictionsStore, dbcPath,"SpellAuraRestrictions.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCastingRequirementsStore, dbcPath,"SpellCastingRequirements.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellEffectStore, dbcPath,"SpellEffect.dbc", &CustomSpellEffectEntryfmt, &CustomSpellEffectEntryIndex);//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCastTimesStore, dbcPath, "SpellCastTimes.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellDifficultyStore, dbcPath, "SpellDifficulty.dbc", &CustomSpellDifficultyfmt, &CustomSpellDifficultyIndex);//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellDurationStore, dbcPath, "SpellDuration.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellFocusObjectStore, dbcPath, "SpellFocusObject.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellItemEnchantmentStore, dbcPath, "SpellItemEnchantment.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellItemEnchantmentConditionStore, dbcPath, "SpellItemEnchantmentCondition.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellRadiusStore, dbcPath, "SpellRadius.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellRangeStore, dbcPath, "SpellRange.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellRuneCostStore, dbcPath, "SpellRuneCost.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellShapeshiftStore, dbcPath, "SpellShapeshift.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSpellShapeshiftFormStore, dbcPath, "SpellShapeshiftForm.dbc");//15595 + //LoadDBC(availableDbcLocales, bad_dbc_files, sStableSlotPricesStore, dbcPath, "StableSlotPrices.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sSummonPropertiesStore, dbcPath, "SummonProperties.dbc");//15595 + + // Must be done when sSkillLineAbilityStore, sSpellStore, sSpellLevelsStore and sCreatureFamilyStore are all loaded for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) { SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j); - if (!skillLine) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId); + if (!spellInfo) + continue; + + SpellLevelsEntry const* levels = sSpellLevelsStore.LookupEntry(spellInfo->SpellLevelsId); + if (spellInfo->SpellLevelsId && (!levels || levels->spellLevel)) + continue; if (spellInfo && spellInfo->Attributes & SPELL_ATTR0_PASSIVE) { @@ -447,8 +600,6 @@ void LoadDBCStores(const std::string& dataPath) if (skillLine->skillId != cFamily->skillLine[0] && skillLine->skillId != cFamily->skillLine[1]) continue; - if (spellInfo->spellLevel) - continue; if (skillLine->AutolearnType != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) continue; @@ -458,21 +609,7 @@ void LoadDBCStores(const std::string& dataPath) } } - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCastTimesStore, dbcPath, "SpellCastTimes.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoryStore, dbcPath, "SpellCategory.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellDifficultyStore, dbcPath, "SpellDifficulty.dbc", &CustomSpellDifficultyfmt, &CustomSpellDifficultyIndex); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellDurationStore, dbcPath, "SpellDuration.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellFocusObjectStore, dbcPath, "SpellFocusObject.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellItemEnchantmentStore, dbcPath, "SpellItemEnchantment.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellItemEnchantmentConditionStore, dbcPath, "SpellItemEnchantmentCondition.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellRadiusStore, dbcPath, "SpellRadius.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellRangeStore, dbcPath, "SpellRange.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellRuneCostStore, dbcPath, "SpellRuneCost.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSpellShapeshiftStore, dbcPath, "SpellShapeshiftForm.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sStableSlotPricesStore, dbcPath, "StableSlotPrices.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSummonPropertiesStore, dbcPath, "SummonProperties.dbc"); - - LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//15595 // Create Spelldifficulty searcher for (uint32 i = 0; i < sSpellDifficultyStore.GetNumRows(); ++i) @@ -483,7 +620,7 @@ void LoadDBCStores(const std::string& dataPath) SpellDifficultyEntry newEntry; memset(newEntry.SpellID, 0, 4*sizeof(uint32)); - for (int x = 0; x < MAX_DIFFICULTY; ++x) + for (uint32 x = 0; x < MAX_DIFFICULTY; ++x) { if (spellDiff->SpellID[x] <= 0 || !sSpellStore.LookupEntry(spellDiff->SpellID[x])) { @@ -494,10 +631,11 @@ void LoadDBCStores(const std::string& dataPath) else newEntry.SpellID[x] = spellDiff->SpellID[x]; } + if (newEntry.SpellID[0] <= 0 || newEntry.SpellID[1] <= 0)//id0-1 must be always set! continue; - for (int x = 0; x < MAX_DIFFICULTY; ++x) + for (uint32 x = 0; x < MAX_DIFFICULTY; ++x) if (newEntry.SpellID[x]) sSpellMgr->SetSpellDifficultyId(uint32(newEntry.SpellID[x]), spellDiff->ID); } @@ -514,7 +652,7 @@ void LoadDBCStores(const std::string& dataPath) sTalentSpellPosMap[talentInfo->RankID[j]] = TalentSpellPos(i, j); } - LoadDBC(availableDbcLocales, bad_dbc_files, sTalentTabStore, dbcPath, "TalentTab.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sTalentTabStore, dbcPath, "TalentTab.dbc");//15595 // prepare fast data access to bit pos of talent ranks for use at inspecting { @@ -536,15 +674,21 @@ void LoadDBCStores(const std::string& dataPath) } } - LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiNodesStore, dbcPath, "TaxiNodes.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiPathStore, dbcPath, "TaxiPath.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sTalentTreePrimarySpellsStore, dbcPath, "TalentTreePrimarySpells.dbc"); + for (uint32 i = 0; i < sTalentTreePrimarySpellsStore.GetNumRows(); ++i) + if (TalentTreePrimarySpellsEntry const* talentSpell = sTalentTreePrimarySpellsStore.LookupEntry(i)) + sTalentTreePrimarySpellsMap[talentSpell->TalentTree].push_back(talentSpell->SpellId); + sTalentTreePrimarySpellsStore.Clear(); + + LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiNodesStore, dbcPath, "TaxiNodes.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiPathStore, dbcPath, "TaxiPath.dbc");//15595 for (uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i) if (TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(i)) sTaxiPathSetBySource[entry->from][entry->to] = TaxiPathBySourceAndDestination(entry->ID, entry->price); uint32 pathCount = sTaxiPathStore.GetNumRows(); //## TaxiPathNode.dbc ## Loaded only for initialization different structures - LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiPathNodeStore, dbcPath, "TaxiPathNode.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiPathNodeStore, dbcPath, "TaxiPathNode.dbc");//15595 // Calculate path nodes count std::vector<uint32> pathLength; pathLength.resize(pathCount); // 0 and some other indexes not used @@ -567,11 +711,10 @@ void LoadDBCStores(const std::string& dataPath) // include existed nodes that have at least single not spell base (scripted) path { std::set<uint32> spellPaths; - for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) - if (SpellEntry const* sInfo = sSpellStore.LookupEntry (i)) - for (int j = 0; j < MAX_SPELL_EFFECTS; ++j) - if (sInfo->Effect[j] == SPELL_EFFECT_SEND_TAXI) - spellPaths.insert(sInfo->EffectMiscValue[j]); + for (uint32 i = 1; i < sSpellEffectStore.GetNumRows(); ++i) + if (SpellEffectEntry const* sInfo = sSpellEffectStore.LookupEntry (i)) + if (sInfo->Effect == SPELL_EFFECT_SEND_TAXI) + spellPaths.insert(sInfo->EffectMiscValue); memset(sTaxiNodesMask, 0, sizeof(sTaxiNodesMask)); memset(sOldContinentsNodesMask, 0, sizeof(sOldContinentsNodesMask)); @@ -603,10 +746,10 @@ void LoadDBCStores(const std::string& dataPath) } // valid taxi network node - uint8 field = (uint8)((i - 1) / 32); - uint32 submask = 1<<((i-1)%32); - sTaxiNodesMask[field] |= submask; + uint8 field = (uint8)((i - 1) / 8); + uint32 submask = 1 << ((i-1) % 8); + sTaxiNodesMask[field] |= submask; if (node->MountCreatureID[0] && node->MountCreatureID[0] != 32981) sHordeTaxiNodesMask[field] |= submask; if (node->MountCreatureID[1] && node->MountCreatureID[1] != 32981) @@ -624,8 +767,8 @@ void LoadDBCStores(const std::string& dataPath) } } - LoadDBC(availableDbcLocales, bad_dbc_files, sTeamContributionPointsStore, dbcPath, "TeamContributionPoints.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sTotemCategoryStore, dbcPath, "TotemCategory.dbc"); + //LoadDBC(availableDbcLocales, bad_dbc_files, sTeamContributionPointsStore, dbcPath, "TeamContributionPoints.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sTotemCategoryStore, dbcPath, "TotemCategory.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sTransportAnimationStore, dbcPath, "TransportAnimation.dbc"); for (uint32 i = 0; i < sTransportAnimationStore.GetNumRows(); ++i) { @@ -646,16 +789,18 @@ void LoadDBCStores(const std::string& dataPath) sTransportMgr->AddPathRotationToTransport(rot->TransportEntry, rot->TimeSeg, rot); } - LoadDBC(availableDbcLocales, bad_dbc_files, sVehicleStore, dbcPath, "Vehicle.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sVehicleSeatStore, dbcPath, "VehicleSeat.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sUnitPowerBarStore, dbcPath, "UnitPowerBar.dbc");//15595 + + LoadDBC(availableDbcLocales, bad_dbc_files, sVehicleStore, dbcPath, "Vehicle.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sVehicleSeatStore, dbcPath, "VehicleSeat.dbc");//15595 - LoadDBC(availableDbcLocales, bad_dbc_files, sWMOAreaTableStore, dbcPath, "WMOAreaTable.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sWMOAreaTableStore, dbcPath, "WMOAreaTable.dbc");//15595 for (uint32 i = 0; i < sWMOAreaTableStore.GetNumRows(); ++i) if (WMOAreaTableEntry const* entry = sWMOAreaTableStore.LookupEntry(i)) sWMOAreaInfoByTripple.insert(WMOAreaInfoByTripple::value_type(WMOAreaTableTripple(entry->rootId, entry->adtId, entry->groupId), entry)); - LoadDBC(availableDbcLocales, bad_dbc_files, sWorldMapAreaStore, dbcPath, "WorldMapArea.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sWorldMapOverlayStore, dbcPath, "WorldMapOverlay.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sWorldSafeLocsStore, dbcPath, "WorldSafeLocs.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sWorldMapAreaStore, dbcPath, "WorldMapArea.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sWorldMapOverlayStore, dbcPath, "WorldMapOverlay.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sWorldSafeLocsStore, dbcPath, "WorldSafeLocs.dbc");//15595 // error checks if (bad_dbc_files.size() >= DBCFileCount) @@ -674,20 +819,25 @@ void LoadDBCStores(const std::string& dataPath) } // Check loaded DBC files proper version - if (!sAreaStore.LookupEntry(3617) || // last area (areaflag) added in 3.3.5a - !sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a - !sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a - !sItemStore.LookupEntry(56806) || // last gem property added in 3.3.5a - !sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a - !sMapStore.LookupEntry(724) || // last map added in 3.3.5a - !sSpellStore.LookupEntry(80864) ) // last client known item added in 3.3.5a + if (!sAreaStore.LookupEntry(4713) || // last area (areaflag) added in 4.3.4 (15595) + !sCharTitlesStore.LookupEntry(287) || // last char title added in 4.3.4 (15595) + !sGemPropertiesStore.LookupEntry(2250) || // last gem property added in 4.3.4 (15595) + !sMapStore.LookupEntry(980) || // last map added in 4.3.4 (15595) + !sSpellStore.LookupEntry(121820) ) // last spell added in 4.3.4 (15595) { TC_LOG_ERROR("misc", "You have _outdated_ DBC files. Please extract correct versions from current using client."); exit(1); } - TC_LOG_INFO("server.loading", ">> Initialized %d data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Initialized %d DBC data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime)); +} + +const std::string* GetRandomCharacterName(uint8 race, uint8 gender) +{ + uint32 size = sGenNameVectoArraysMap[race].stringVectorArray[gender].size(); + uint32 randPos = urand(0, size-1); + return &sGenNameVectoArraysMap[race].stringVectorArray[gender][randPos]; } SimpleFactionsList const* GetFactionTeamList(uint32 faction) @@ -699,14 +849,14 @@ SimpleFactionsList const* GetFactionTeamList(uint32 faction) return NULL; } -char* GetPetName(uint32 petfamily, uint32 dbclang) +char const* GetPetName(uint32 petfamily, uint32 /*dbclang*/) { if (!petfamily) return NULL; CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(petfamily); if (!pet_family) return NULL; - return pet_family->Name[dbclang]?pet_family->Name[dbclang]:NULL; + return pet_family->Name ? pet_family->Name : NULL; } TalentSpellPos const* GetTalentSpellPos(uint32 spellId) @@ -763,16 +913,16 @@ AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_ return NULL; } -char const* GetRaceName(uint8 race, uint8 locale) +char const* GetRaceName(uint8 race, uint8 /*locale*/) { ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race); - return raceEntry ? raceEntry->name[locale] : NULL; + return raceEntry ? raceEntry->name : NULL; } -char const* GetClassName(uint8 class_, uint8 locale) +char const* GetClassName(uint8 class_, uint8 /*locale*/) { ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); - return classEntry ? classEntry->name[locale] : NULL; + return classEntry ? classEntry->name : NULL; } uint32 GetAreaFlagByMapId(uint32 mapid) @@ -786,7 +936,7 @@ uint32 GetAreaFlagByMapId(uint32 mapid) uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId) { - if (mapid != 530 && mapid != 571) // speed for most cases + if (mapid != 530 && mapid != 571 && mapid != 732) // speed for most cases return mapid; if (WorldMapAreaEntry const* wma = sWorldMapAreaStore.LookupEntry(zoneId)) @@ -795,6 +945,28 @@ uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId) return mapid; } +uint32 GetMaxLevelForExpansion(uint32 expansion) +{ + switch (expansion) + { + case CONTENT_1_60: + return 60; + case CONTENT_61_70: + return 70; + case CONTENT_71_80: + return 80; + case CONTENT_81_85: + return 85; + default: + break; + } + return 0; +} + +/* +Used only for calculate xp gain by content lvl. +Calculation on Gilneas and group maps of LostIslands calculated as CONTENT_1_60. +*/ ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId) { mapid = GetVirtualMapForMapAndZone(mapid, zoneId); @@ -805,11 +977,17 @@ ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId) if (!mapEntry) return CONTENT_1_60; - switch (mapEntry->Expansion()) + // no need enum all maps from phasing + if (mapEntry->rootPhaseMap >= 0) + mapid = mapEntry->rootPhaseMap; + + switch (mapid) { - default: return CONTENT_1_60; - case 1: return CONTENT_61_70; - case 2: return CONTENT_71_80; + case 648: //LostIslands + case 654: //Gilneas + return CONTENT_1_60; + default: + return ContentLevels(mapEntry->Expansion()); } } @@ -928,6 +1106,15 @@ uint32 const* GetTalentTabPages(uint8 cls) return sTalentTabPages[cls]; } +std::vector<uint32> const* GetTalentTreePrimarySpells(uint32 talentTree) +{ + TalentTreePrimarySpellsMap::const_iterator itr = sTalentTreePrimarySpellsMap.find(talentTree); + if (itr == sTalentTreePrimarySpellsMap.end()) + return NULL; + + return &itr->second; +} + uint32 GetLiquidFlags(uint32 liquidType) { if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquidType)) @@ -945,6 +1132,163 @@ CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, ui return itr->second; } +uint32 GetPowerIndexByClass(uint32 powerType, uint32 classId) +{ + return PowersByClass[classId][powerType]; +} + +uint32 ScalingStatValuesEntry::GetStatMultiplier(uint32 inventoryType) const +{ + if (inventoryType < MAX_INVTYPE) + { + switch (inventoryType) + { + case INVTYPE_NON_EQUIP: + case INVTYPE_BODY: + case INVTYPE_BAG: + case INVTYPE_TABARD: + case INVTYPE_AMMO: + case INVTYPE_QUIVER: + return 0; + case INVTYPE_HEAD: + case INVTYPE_CHEST: + case INVTYPE_LEGS: + case INVTYPE_2HWEAPON: + case INVTYPE_ROBE: + return StatMultiplier[0]; + case INVTYPE_SHOULDERS: + case INVTYPE_WAIST: + case INVTYPE_FEET: + case INVTYPE_HANDS: + case INVTYPE_TRINKET: + return StatMultiplier[1]; + case INVTYPE_NECK: + case INVTYPE_WRISTS: + case INVTYPE_FINGER: + case INVTYPE_SHIELD: + case INVTYPE_CLOAK: + case INVTYPE_HOLDABLE: + return StatMultiplier[2]; + case INVTYPE_RANGED: + case INVTYPE_THROWN: + case INVTYPE_RANGEDRIGHT: + case INVTYPE_RELIC: + return StatMultiplier[3]; + case INVTYPE_WEAPON: + case INVTYPE_WEAPONMAINHAND: + case INVTYPE_WEAPONOFFHAND: + return StatMultiplier[4]; + default: + break; + } + } + return 0; +} + +uint32 ScalingStatValuesEntry::GetArmor(uint32 inventoryType, uint32 armorType) const +{ + if (inventoryType <= INVTYPE_ROBE && armorType < 4) + { + switch (inventoryType) + { + case INVTYPE_NON_EQUIP: + case INVTYPE_NECK: + case INVTYPE_BODY: + case INVTYPE_FINGER: + case INVTYPE_TRINKET: + case INVTYPE_WEAPON: + case INVTYPE_SHIELD: + case INVTYPE_RANGED: + case INVTYPE_2HWEAPON: + case INVTYPE_BAG: + case INVTYPE_TABARD: + break; + case INVTYPE_SHOULDERS: + return Armor[0][armorType]; + case INVTYPE_CHEST: + case INVTYPE_ROBE: + return Armor[1][armorType]; + case INVTYPE_HEAD: + return Armor[2][armorType]; + case INVTYPE_LEGS: + return Armor[3][armorType]; + case INVTYPE_FEET: + return Armor[4][armorType]; + case INVTYPE_WAIST: + return Armor[5][armorType]; + case INVTYPE_HANDS: + return Armor[6][armorType]; + case INVTYPE_WRISTS: + return Armor[7][armorType]; + case INVTYPE_CLOAK: + return CloakArmor; + default: + break; + } + } + return 0; +} + +uint32 ScalingStatValuesEntry::GetDPSAndDamageMultiplier(uint32 subClass, bool isCasterWeapon, float* damageMultiplier) const +{ + if (!isCasterWeapon) + { + switch (subClass) + { + case ITEM_SUBCLASS_WEAPON_AXE: + case ITEM_SUBCLASS_WEAPON_MACE: + case ITEM_SUBCLASS_WEAPON_SWORD: + case ITEM_SUBCLASS_WEAPON_DAGGER: + case ITEM_SUBCLASS_WEAPON_THROWN: + *damageMultiplier = 0.3f; + return dpsMod[0]; + case ITEM_SUBCLASS_WEAPON_AXE2: + case ITEM_SUBCLASS_WEAPON_MACE2: + case ITEM_SUBCLASS_WEAPON_POLEARM: + case ITEM_SUBCLASS_WEAPON_SWORD2: + case ITEM_SUBCLASS_WEAPON_STAFF: + case ITEM_SUBCLASS_WEAPON_FISHING_POLE: + *damageMultiplier = 0.2f; + return dpsMod[1]; + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_GUN: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + *damageMultiplier = 0.3f; + return dpsMod[4]; + case ITEM_SUBCLASS_WEAPON_Obsolete: + case ITEM_SUBCLASS_WEAPON_EXOTIC: + case ITEM_SUBCLASS_WEAPON_EXOTIC2: + case ITEM_SUBCLASS_WEAPON_FIST_WEAPON: + case ITEM_SUBCLASS_WEAPON_MISCELLANEOUS: + case ITEM_SUBCLASS_WEAPON_SPEAR: + case ITEM_SUBCLASS_WEAPON_WAND: + break; + } + } + else + { + if (subClass <= ITEM_SUBCLASS_WEAPON_WAND) + { + uint32 mask = 1 << subClass; + // two-handed weapons + if (mask & 0x562) + { + *damageMultiplier = 0.2f; + return dpsMod[3]; + } + + if (mask & (1 << ITEM_SUBCLASS_WEAPON_WAND)) + { + *damageMultiplier = 0.3f; + return dpsMod[5]; + } + } + *damageMultiplier = 0.3f; + return dpsMod[2]; + } + return 0; +} + /// Returns LFGDungeonEntry for a specific map and difficulty. Will return first found entry if multiple dungeons use the same map (such as Scarlet Monastery) LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty) { @@ -991,3 +1335,8 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u return NULL; } + +std::set<uint32> const& GetPhasesForGroup(uint32 group) +{ + return sPhasesByGroup[group]; +} diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 8b89a86fafe..eeaa45c9042 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -28,7 +28,7 @@ typedef std::list<uint32> SimpleFactionsList; SimpleFactionsList const* GetFactionTeamList(uint32 faction); -char* GetPetName(uint32 petfamily, uint32 dbclang); +char const* GetPetName(uint32 petfamily, uint32 dbclang); uint32 GetTalentSpellCost(uint32 spellId); TalentSpellPos const* GetTalentSpellPos(uint32 spellId); @@ -44,12 +44,19 @@ WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId); +const std::string* GetRandomCharacterName(uint8 race, uint8 gender); + enum ContentLevels { - CONTENT_1_60 = 0, - CONTENT_61_70, - CONTENT_71_80 + CONTENT_1_60 = 0, + CONTENT_61_70 = 1, + CONTENT_71_80 = 2, + CONTENT_81_85 = 3, + MAX_CONTENT }; + +uint32 GetMaxLevelForExpansion(uint32 expansion); + ContentLevels GetContentLevelsForMapAndZone(uint32 mapid, uint32 zoneId); bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId); @@ -62,6 +69,7 @@ MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty); uint32 const* /*[MAX_TALENT_TABS]*/ GetTalentTabPages(uint8 cls); +std::vector<uint32> const* GetTalentTreePrimarySpells(uint32 talentTree); uint32 GetLiquidFlags(uint32 liquidType); @@ -70,10 +78,13 @@ PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundB CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender); +uint32 GetPowerIndexByClass(uint32 powerType, uint32 classId); LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty); uint32 GetDefaultMapLight(uint32 mapId); +std::set<uint32> const& GetPhasesForGroup(uint32 group); + typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRaceClassInfoMap; typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds; SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); @@ -84,6 +95,7 @@ extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access extern DBCStorage <AreaGroupEntry> sAreaGroupStore; extern DBCStorage <AreaPOIEntry> sAreaPOIStore; extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore; +extern DBCStorage <ArmorLocationEntry> sArmorLocationStore; extern DBCStorage <AuctionHouseEntry> sAuctionHouseStore; extern DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore; extern DBCStorage <BannedAddOnsEntry> sBannedAddOnsStore; @@ -94,6 +106,7 @@ extern DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore; extern DBCStorage <CharTitlesEntry> sCharTitlesStore; extern DBCStorage <ChrClassesEntry> sChrClassesStore; extern DBCStorage <ChrRacesEntry> sChrRacesStore; +extern DBCStorage <ChrPowerTypesEntry> sChrPowerTypesStore; extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore; extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore; extern DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore; @@ -123,15 +136,35 @@ extern DBCStorage <GtChanceToSpellCritBaseEntry> sGtChanceToSpellCritBaseStore; extern DBCStorage <GtChanceToSpellCritEntry> sGtChanceToSpellCritStore; extern DBCStorage <GtNPCManaCostScalerEntry> sGtNPCManaCostScalerStore; extern DBCStorage <GtOCTClassCombatRatingScalarEntry> sGtOCTClassCombatRatingScalarStore; -extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore; //extern DBCStorage <GtOCTRegenMPEntry> sGtOCTRegenMPStore; -- not used currently -extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore; +extern DBCStorage <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore; extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore; +extern DBCStorage <GtSpellScalingEntry> sGtSpellScalingStore; +extern DBCStorage <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore; +extern DBCStorage <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore; +extern DBCStorage <GuildPerkSpellsEntry> sGuildPerkSpellsStore; extern DBCStorage <HolidaysEntry> sHolidaysStore; -extern DBCStorage <ItemEntry> sItemStore; +extern DBCStorage <ImportPriceArmorEntry> sImportPriceArmorStore; +extern DBCStorage <ImportPriceQualityEntry> sImportPriceQualityStore; +extern DBCStorage <ImportPriceShieldEntry> sImportPriceShieldStore; +extern DBCStorage <ImportPriceWeaponEntry> sImportPriceWeaponStore; +extern DBCStorage <ItemPriceBaseEntry> sItemPriceBaseStore; +extern DBCStorage <ItemReforgeEntry> sItemReforgeStore; +extern DBCStorage <ItemArmorQualityEntry> sItemArmorQualityStore; +extern DBCStorage <ItemArmorShieldEntry> sItemArmorShieldStore; +extern DBCStorage <ItemArmorTotalEntry> sItemArmorTotalStore; +extern DBCStorage <ItemClassEntry> sItemClassStore; extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore; +extern DBCStorage <ItemDamageEntry> sItemDamageAmmoStore; +extern DBCStorage <ItemDamageEntry> sItemDamageOneHandStore; +extern DBCStorage <ItemDamageEntry> sItemDamageOneHandCasterStore; +extern DBCStorage <ItemDamageEntry> sItemDamageRangedStore; +extern DBCStorage <ItemDamageEntry> sItemDamageThrownStore; +extern DBCStorage <ItemDamageEntry> sItemDamageTwoHandStore; +extern DBCStorage <ItemDamageEntry> sItemDamageTwoHandCasterStore; +extern DBCStorage <ItemDamageEntry> sItemDamageWandStore; //extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore; -- not used currently -extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore; +extern DBCStorage <ItemDisenchantLootEntry> sItemDisenchantLootStore; extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore; extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore; extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore; @@ -141,6 +174,12 @@ extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore; extern DBCStorage <LockEntry> sLockStore; extern DBCStorage <MailTemplateEntry> sMailTemplateStore; extern DBCStorage <MapEntry> sMapStore; +extern DBCStorage <MountCapabilityEntry> sMountCapabilityStore; +extern DBCStorage <MountTypeEntry> sMountTypeStore; +extern DBCStorage <NameGenEntry> sNameGenStore; +extern DBCStorage <NumTalentsAtLevelEntry> sNumTalentsAtLevelStore; +extern DBCStorage <PhaseEntry> sPhaseStore; +extern DBCStorage <PhaseGroupEntry> sPhaseGroupStore; //extern DBCStorage <MapDifficultyEntry> sMapDifficultyStore; -- use GetMapDifficultyData insteed extern MapDifficultyMap sMapDifficultyMap; extern DBCStorage <MovieEntry> sMovieStore; @@ -169,8 +208,24 @@ extern DBCStorage <SpellRadiusEntry> sSpellRadiusStore; extern DBCStorage <SpellRangeEntry> sSpellRangeStore; extern DBCStorage <SpellRuneCostEntry> sSpellRuneCostStore; extern DBCStorage <SpellShapeshiftEntry> sSpellShapeshiftStore; +extern DBCStorage <SpellShapeshiftFormEntry> sSpellShapeshiftFormStore; extern DBCStorage <SpellEntry> sSpellStore; -extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore; +extern DBCStorage <SpellAuraOptionsEntry> sSpellAuraOptionsStore; +extern DBCStorage <SpellAuraRestrictionsEntry> sSpellAuraRestrictionsStore; +extern DBCStorage <SpellCastingRequirementsEntry> sSpellCastingRequirementsStore; +extern DBCStorage <SpellCategoriesEntry> sSpellCategoriesStore; +extern DBCStorage <SpellClassOptionsEntry> sSpellClassOptionsStore; +extern DBCStorage <SpellCooldownsEntry> sSpellCooldownsStore; +extern DBCStorage <SpellEffectEntry> sSpellEffectStore; +extern DBCStorage <SpellEquippedItemsEntry> sSpellEquippedItemsStore; +extern DBCStorage <SpellInterruptsEntry> sSpellInterruptsStore; +extern DBCStorage <SpellLevelsEntry> sSpellLevelsStore; +extern DBCStorage <SpellPowerEntry> sSpellPowerStore; +extern DBCStorage <SpellReagentsEntry> sSpellReagentsStore; +extern DBCStorage <SpellScalingEntry> sSpellScalingStore; +extern DBCStorage <SpellTargetRestrictionsEntry> sSpellTargetRestrictionsStore; +extern DBCStorage <SpellTotemsEntry> sSpellTotemsStore; +//extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore; extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore; extern DBCStorage <TalentEntry> sTalentStore; extern DBCStorage <TalentTabEntry> sTalentTabStore; @@ -183,8 +238,8 @@ extern TaxiMask sAllianceTaxiNodesMask; extern TaxiMask sDeathKnightTaxiNodesMask; extern TaxiPathSetBySource sTaxiPathSetBySource; extern TaxiPathNodesByPath sTaxiPathNodesByPath; -extern DBCStorage <TeamContributionPointsEntry> sTeamContributionPointsStore; extern DBCStorage <TotemCategoryEntry> sTotemCategoryStore; +extern DBCStorage <UnitPowerBarEntry> sUnitPowerBarStore; extern DBCStorage <VehicleEntry> sVehicleStore; extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore; extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 1e1cd6dd9d6..001392aee4c 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -44,35 +44,31 @@ struct AchievementEntry int32 requiredFaction; // 1 -1=all, 0=horde, 1=alliance int32 mapID; // 2 -1=none //uint32 parentAchievement; // 3 its Achievement parent (can`t start while parent uncomplete, use its Criteria if don`t have own, use its progress on begin) - char *name[16]; // 4-19 - //uint32 name_flags; // 20 - //char *description[16]; // 21-36 - //uint32 desc_flags; // 37 - uint32 categoryId; // 38 - uint32 points; // 39 reward points - //uint32 OrderInCategory; // 40 - uint32 flags; // 41 - //uint32 icon; // 42 icon (from SpellIcon.dbc) - //char *titleReward[16]; // 43-58 - //uint32 titleReward_flags; // 59 - uint32 count; // 60 - need this count of completed criterias (own or referenced achievement criterias) - uint32 refAchievement; // 61 - referenced achievement (counting of all completed criterias) + char* name; // 4 + //char* description; // 5 + uint32 categoryId; // 6 + uint32 points; // 7 reward points + //uint32 OrderInCategory; // 8 + uint32 flags; // 9 + //uint32 icon; // 10 icon (from SpellIcon.dbc) + //char* reward; // 11 + uint32 count; // 12 - need this count of completed criterias (own or referenced achievement criterias) + uint32 refAchievement; // 13 - referenced achievement (counting of all completed criterias) }; struct AchievementCategoryEntry { uint32 ID; // 0 uint32 parentCategory; // 1 -1 for main category - //char *name[16]; // 2-17 - //uint32 name_flags; // 18 - //uint32 sortOrder; // 19 + //char* name; // 2 + //uint32 sortOrder; // 3 }; struct AchievementCriteriaEntry { uint32 ID; // 0 - uint32 referredAchievement; // 1 - uint32 requiredType; // 2 + uint32 achievement; // 1 + uint32 type; // 2 union { // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0 @@ -80,28 +76,29 @@ struct AchievementCriteriaEntry struct { uint32 creatureID; // 3 - uint32 creatureCount; // 4 + uint64 creatureCount; // 4 } kill_creature; // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1 struct { uint32 bgMapID; // 3 - uint32 winCount; // 4 + uint64 winCount; // 4 } win_bg; // ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5 + // ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL = 125 struct { uint32 unused; // 3 - uint32 level; // 4 + uint64 level; // 4 } reach_level; // ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7 struct { uint32 skillID; // 3 - uint32 skillLevel; // 4 + uint64 skillLevel; // 4 } reach_skill_level; // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8 @@ -114,28 +111,35 @@ struct AchievementCriteriaEntry struct { uint32 unused; // 3 - uint32 totalQuestCount; // 4 + uint64 totalQuestCount; // 4 } complete_quest_count; // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10 struct { uint32 unused; // 3 - uint32 numberOfDays; // 4 + uint64 numberOfDays; // 4 } complete_daily_quest_daily; // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11 struct { uint32 zoneID; // 3 - uint32 questCount; // 4 + uint64 questCount; // 4 } complete_quests_in_zone; + // ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12 + struct + { + uint32 currency; + uint64 count; + } currencyGain; + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14 struct { uint32 unused; // 3 - uint32 questCount; // 4 + uint64 questCount; // 4 } complete_daily_quest; // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15 @@ -172,7 +176,7 @@ struct AchievementCriteriaEntry struct { uint32 unused; // 3 - uint32 fallHeight; // 4 + uint64 fallHeight; // 4 } fall_without_dying; // ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26 @@ -185,7 +189,7 @@ struct AchievementCriteriaEntry struct { uint32 questID; // 3 - uint32 questCount; // 4 + uint64 questCount; // 4 } complete_quest; // ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28 @@ -193,7 +197,7 @@ struct AchievementCriteriaEntry struct { uint32 spellID; // 3 - uint32 spellCount; // 4 + uint64 spellCount; // 4 } be_spell_target; // ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29 @@ -201,28 +205,28 @@ struct AchievementCriteriaEntry struct { uint32 spellID; // 3 - uint32 castCount; // 4 + uint64 castCount; // 4 } cast_spell; // ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE struct { uint32 objectiveId; // 3 - uint32 completeCount; // 4 + uint64 completeCount; // 4 } bg_objective; // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 struct { uint32 areaID; // 3 Reference to AreaTable.dbc - uint32 killCount; // 4 + uint64 killCount; // 4 } honorable_kill_at_area; // ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32 struct { uint32 mapID; // 3 Reference to Map.dbc - uint32 count; // 4 Number of times that the arena must be won. + uint64 count; // 4 Number of times that the arena must be won. } win_arena; // ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33 @@ -241,14 +245,14 @@ struct AchievementCriteriaEntry struct { uint32 itemID; // 3 - uint32 itemCount; // 4 + uint64 itemCount; // 4 } own_item; // ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37 struct { uint32 unused; // 3 - uint32 count; // 4 + uint64 count; // 4 } win_rated_arena; // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 @@ -261,28 +265,35 @@ struct AchievementCriteriaEntry struct { uint32 teamtype; // 3 {2, 3, 5} - uint32 PersonalRating; // 4 + uint64 teamrating; // 4 + } reach_team_rating; + + // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39 + struct + { + uint32 teamtype; // 3 {2, 3, 5} + uint64 PersonalRating; // 4 } highest_personal_rating; // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40 struct { uint32 skillID; // 3 - uint32 skillLevel; // 4 apprentice=1, journeyman=2, expert=3, artisan=4, master=5, grand master=6 + uint64 skillLevel; // 4 apprentice=1, journeyman=2, expert=3, artisan=4, master=5, grand master=6 } learn_skill_level; // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41 struct { uint32 itemID; // 3 - uint32 itemCount; // 4 + uint64 itemCount; // 4 } use_item; // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42 struct { uint32 itemID; // 3 - uint32 itemCount; // 4 + uint64 itemCount; // 4 } loot_item; // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43 @@ -303,28 +314,28 @@ struct AchievementCriteriaEntry struct { uint32 unused; // 3 - uint32 numberOfSlots; // 4 + uint64 numberOfSlots; // 4 } buy_bank_slot; // ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46 struct { uint32 factionID; // 3 - uint32 reputationAmount; // 4 Total reputation amount, so 42000 = exalted + uint64 reputationAmount; // 4 Total reputation amount, so 42000 = exalted } gain_reputation; // ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION= 47 struct { uint32 unused; // 3 - uint32 numberOfExaltedFactions; // 4 + uint64 numberOfExaltedFactions; // 4 } gain_exalted_reputation; // ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48 struct { uint32 unused; // 3 - uint32 numberOfVisits; // 4 + uint64 numberOfVisits; // 4 } visit_barber; // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49 @@ -332,34 +343,34 @@ struct AchievementCriteriaEntry struct { uint32 itemSlot; // 3 - uint32 count; // 4 + uint64 count; // 4 } equip_epic_item; // ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50 struct { uint32 rollValue; // 3 - uint32 count; // 4 + uint64 count; // 4 } roll_need_on_loot; // ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51 struct { uint32 rollValue; // 3 - uint32 count; // 4 + uint64 count; // 4 } roll_greed_on_loot; // ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52 struct { uint32 classID; // 3 - uint32 count; // 4 + uint64 count; // 4 } hk_class; // ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53 struct { uint32 raceID; // 3 - uint32 count; // 4 + uint64 count; // 4 } hk_race; // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54 @@ -367,49 +378,50 @@ struct AchievementCriteriaEntry struct { uint32 emoteID; // 3 enum TextEmotes - uint32 count; // 4 count of emotes, always required special target or requirements + uint64 count; // 4 count of emotes, always required special target or requirements } do_emote; // ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13 // ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55 + // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56 struct { uint32 unused; // 3 - uint32 count; // 4 + uint64 count; // 4 } healing_done; // ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56 struct { uint32 unused; - uint32 killCount; + uint64 killCount; } get_killing_blow; // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57 struct { uint32 itemID; // 3 - uint32 count; // 4 + uint64 count; // 4 } equip_item; // ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD= 62 struct { uint32 unused; // 3 - uint32 goldInCopper; // 4 + uint64 goldInCopper; // 4 } quest_reward_money; // ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67 struct { uint32 unused; // 3 - uint32 goldInCopper; // 4 + uint64 goldInCopper; // 4 } loot_money; // ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68 struct { uint32 goEntry; // 3 - uint32 useCount; // 4 + uint64 useCount; // 4 } use_gameobject; // ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70 @@ -417,28 +429,28 @@ struct AchievementCriteriaEntry struct { uint32 unused; // 3 - uint32 killCount; // 4 + uint64 killCount; // 4 } special_pvp_kill; // ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72 struct { uint32 goEntry; // 3 - uint32 lootCount; // 4 + uint64 lootCount; // 4 } fish_in_gameobject; // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75 struct { uint32 skillLine; // 3 - uint32 spellCount; // 4 + uint64 spellCount; // 4 } learn_skillline_spell; // ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76 struct { uint32 unused; // 3 - uint32 duelCount; // 4 + uint64 duelCount; // 4 } win_duel; // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96 @@ -469,33 +481,33 @@ struct AchievementCriteriaEntry struct { uint32 lootType; // 3 3=fishing, 2=pickpocket, 4=disentchant - uint32 lootTypeCount; // 4 + uint64 lootTypeCount; // 4 } loot_type; // ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112 struct { uint32 skillLine; // 3 - uint32 spellCount; // 4 + uint64 spellCount; // 4 } learn_skill_line; // ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113 struct { uint32 unused; // 3 - uint32 killCount; // 4 + uint64 killCount; // 4 } honorable_kill; struct { uint32 unused; - uint32 dungeonsComplete; + uint64 dungeonsComplete; } use_lfg; struct { uint32 field3; // 3 main requirement - uint32 count; // 4 main requirement count + uint64 count; // 4 main requirement count } raw; }; @@ -505,15 +517,19 @@ struct AchievementCriteriaEntry uint32 additionalRequirement_value; } additionalRequirements[MAX_CRITERIA_REQUIREMENTS]; - //char* name[16]; // 9-24 - //uint32 name_flags; // 25 - uint32 flags; // 26 - uint32 timedType; // 27 - uint32 timerStartEvent; // 28 Alway appears with timed events - // for timed spells it is spell id for - // timed kills it is creature id - uint32 timeLimit; // 29 time limit in seconds - //uint32 showOrder; // 30 show order + char* name; // 9 m_description_lang + uint32 completionFlag; // 10 m_flags + uint32 timedCriteriaStartType; // 11 m_timer_start_event Only appears with timed achievements, seems to be the type of starting a timed Achievement, only type 1 and some of type 6 need manual starting + // 1: ByEventId(?) (serverside IDs), 2: ByQuestId, 5: ByCastSpellId(?) + // 6: BySpellIdTarget(some of these are unknown spells, some not, some maybe spells) + // 7: ByKillNpcId, 9: ByUseItemId + uint32 timedCriteriaMiscId; // 12 m_timer_asset_id Alway appears with timed events, used internally to start the achievement, store + uint32 timeLimit; // 13 m_timer_time time limit in seconds + uint32 showOrder; // 14 m_ui_order also used in achievement shift-links as index in state bitmask + //uint32 unk1; // 15 only one value, still unknown + //uint32 unk2; // 16 all zeros + uint32 additionalConditionType[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 17-19 + uint32 additionalConditionValue[MAX_ADDITIONAL_CRITERIA_CONDITIONS]; // 20-22 }; struct AreaTableEntry @@ -522,13 +538,25 @@ struct AreaTableEntry uint32 mapid; // 1 uint32 zone; // 2 if 0 then it's zone, else it's zone id of this area uint32 exploreFlag; // 3, main index - uint32 flags; // 4, unknown value but 312 for all cities - // 5-9 unused + uint32 flags; // 4, + //uint32 unk5; // 5, + //uint32 unk6; // 6, + //uint32 unk7; // 7, + //uint32 unk8; // 8, + //uint32 unk9; // 9, int32 area_level; // 10 - char* area_name[16]; // 11-26 - // 27, string flags, unused - uint32 team; // 28 - uint32 LiquidTypeOverride[4]; // 29-32 liquid override by type + char* area_name; // 11 + uint32 team; // 12 + uint32 LiquidTypeOverride[4]; // 13-16 liquid override by type + float MaxDepth; // 17, + float AmbientMultiplier; // 18 client only? + uint32 LightId; // 19 + //uint32 unk20; // 20 4.0.0 - Mounting related + //uint32 unk21; // 21 4.0.0 + //uint32 unk22; // 22 4.0.0 + //uint32 unk23; // 23 4.0.0 + //uint32 unk24; // 24 - worldStateId + //uint32 unk25 // 25 // helpers bool IsSanctuary() const @@ -554,16 +582,14 @@ struct AreaPOIEntry uint32 icon[11]; //1-11 float x; //12 float y; //13 - float z; //14 - uint32 mapId; //15 - //uint32 val1; //16 - uint32 zoneId; //17 - //char* name[16]; //18-33 - //uint32 name_flag; //34 - //char* name2[16]; //35-50 - //uint32 name_flag2; //51 - uint32 worldState; //52 - //uint32 val2; //53 + uint32 mapId; //14 + //uint32 val1; //15 + uint32 zoneId; //16 + //char* name; //17 - name + //char* name2; //18 - name2 + uint32 worldState; //19 + //uint32 val2; //20 + //uint32 unk; //21 }; struct AreaTriggerEntry @@ -573,11 +599,20 @@ struct AreaTriggerEntry float x; // 2 m_x float y; // 3 m_y float z; // 4 m_z - float radius; // 5 m_radius - float box_x; // 6 m_box_length - float box_y; // 7 m_box_width - float box_z; // 8 m_box_heigh - float box_orientation; // 9 m_box_yaw + //uint32 // 5 + //uint32 // 6 + //uint32 // 7 + float radius; // 8 m_radius + float box_x; // 9 m_box_length + float box_y; // 10 m_box_width + float box_z; // 11 m_box_heigh + float box_orientation; // 12 m_box_yaw +}; + +struct ArmorLocationEntry +{ + uint32 InventoryType; // 0 + float Value[5]; // 1-5 multiplier for armor types (cloth...plate, no armor?) }; struct AuctionHouseEntry @@ -586,8 +621,7 @@ struct AuctionHouseEntry uint32 faction; // 1 id of faction.dbc for player factions associated with city uint32 depositPercent; // 2 1/3 from real uint32 cutPercent; // 3 - //char* name[16]; // 4-19 - // 20 string flag, unused + //char* name; // 4 }; struct BankBagSlotPricesEntry @@ -609,14 +643,12 @@ struct BarberShopStyleEntry { uint32 Id; // 0 uint32 type; // 1 value 0 -> hair, value 2 -> facialhair - //char* name[16]; // 2-17 name of hair style - //uint32 name_flags; // 18 - //uint32 unk_name[16]; // 19-34, all empty - //uint32 unk_flags; // 35 - //float CostMultiplier; // 36 values 1 and 0.75 - uint32 race; // 37 race - uint32 gender; // 38 0 -> male, 1 -> female - uint32 hair_id; // 39 real ID to hair/facial hair + //char* name; // 2 m_DisplayName_lang + //uint32 unk_name; // 3 m_Description_lang + //float CostMultiplier; // 4 m_Cost_Modifier + uint32 race; // 5 m_race + uint32 gender; // 6 m_sex + uint32 hair_id; // 7 m_data (real ID to hair/facial hair) }; struct BattlemasterListEntry @@ -625,12 +657,15 @@ struct BattlemasterListEntry int32 mapid[8]; // 1-8 mapid uint32 type; // 9 map type (3 - BG, 4 - arena) //uint32 canJoinAsGroup; // 10 (0 or 1) - char* name[16]; // 11-26 - //uint32 nameFlags // 27 string flag, unused - uint32 maxGroupSize; // 28 maxGroupSize, used for checking if queue as group - uint32 HolidayWorldStateId; // 29 new 3.1 - //uint32 MinLevel; // 30 - //uint32 SomeLevel; // 31, may be max level + char* name; // 11 + uint32 maxGroupSize; // 12 maxGroupSize, used for checking if queue as group + uint32 HolidayWorldStateId; // 13 new 3.1 + uint32 minLevel; // 14, min level (sync with PvPDifficulty.dbc content) + uint32 maxLevel; // 15, max level (sync with PvPDifficulty.dbc content) + //uint32 maxGroupSizeRated; // 16 4.0.1 + //uint32 unk; // 17 - 4.0.6.13596 + //uint32 maxPlayers; // 18 4.0.1 + //uint32 unk1; // 19 4.0.3, value 2 for Rated Battlegrounds }; #define MAX_OUTFIT_ITEMS 24 @@ -645,46 +680,45 @@ struct CharStartOutfitEntry int32 ItemId[MAX_OUTFIT_ITEMS]; // 5-28 //int32 ItemDisplayId[MAX_OUTFIT_ITEMS]; // 29-52 not required at server side //int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 53-76 not required at server side + uint32 PetDisplayId; // 77 Pet Model ID for starting pet + uint32 PetFamilyEntry; // 78 Pet Family Entry for starting pet }; struct CharTitlesEntry { uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId() //uint32 unk1; // 1 flags? - char* nameMale[16]; // 2-17 - // 18 string flag, unused - char* nameFemale[16]; // 19-34 - // 35 string flag, unused - uint32 bit_index; // 36 used in PLAYER_CHOSEN_TITLE and 1<<index in PLAYER__FIELD_KNOWN_TITLES + char* nameMale; // 2 m_name_lang + char* nameFemale; // 3 m_name1_lang + uint32 bit_index; // 4 m_mask_ID used in PLAYER_CHOSEN_TITLE and 1<<index in PLAYER__FIELD_KNOWN_TITLES + //uint32 // 5 }; struct ChatChannelsEntry { uint32 ChannelID; // 0 uint32 flags; // 1 - char* pattern[16]; // 3-18 - // 19 string flags, unused - //char* name[16]; // 20-35 unused - // 36 string flag, unused + //uint32 // 2 m_factionGroup + char* pattern; // 3 m_name_lang + //char* name; // 4 m_shortcut_lang }; struct ChrClassesEntry { uint32 ClassID; // 0 - // 1, unused - uint32 powerType; // 2 - // 3-4, unused - char* name[16]; // 5-20 unused - // 21 string flag, unused - //char* nameFemale[16]; // 21-36 unused, if different from base (male) case - // 37 string flag, unused - //char* nameNeutralGender[16]; // 38-53 unused, if different from base (male) case - // 54 string flag, unused - // 55, unused - uint32 spellfamily; // 56 - // 57, unused - uint32 CinematicSequence; // 58 id from CinematicSequences.dbc - uint32 expansion; // 59 (0 - original race, 1 - tbc addon, ...) + uint32 powerType; // 1 m_DisplayPower + // 2 m_petNameToken + char* name; // 3 m_name_lang + //char* nameFemale; // 4 m_name_female_lang + //char* nameNeutralGender; // 5 m_name_male_lang + //char* capitalizedName // 6, m_filename + uint32 spellfamily; // 7 m_spellClassSet + //uint32 flags2; // 8 m_flags (0x08 HasRelicSlot) + uint32 CinematicSequence; // 9 m_cinematicSequenceID + uint32 expansion; // 10 m_required_expansion + uint32 APPerStrenth; // 11 Attack Power bonus per point of strength + uint32 APPerAgility; // 12 Attack Power bonus per point of agility + uint32 RAPPerAgility; // 13 Ranged Attack Power bonus per point of agility }; struct ChrRacesEntry @@ -699,15 +733,23 @@ struct ChrRacesEntry uint32 TeamID; // 7 (7-Alliance 1-Horde) // 8-11 unused uint32 CinematicSequence; // 12 id from CinematicSequences.dbc - //uint32 unk_322; // 13 faction (0 alliance, 1 horde, 2 not available?) - char* name[16]; // 14-29 used for DBC language detection/selection - // 30 string flags, unused - //char* nameFemale[16]; // 31-46, if different from base (male) case - // 47 string flags, unused - //char* nameNeutralGender[16]; // 48-63, if different from base (male) case - // 64 string flags, unused - // 65-67 unused - uint32 expansion; // 68 (0 - original race, 1 - tbc addon, ...) + //uint32 unk_322; // 13 m_alliance (0 alliance, 1 horde, 2 not available?) + char* name; // 14 m_name_lang used for DBC language detection/selection + //char* nameFemale; // 15 m_name_female_lang + //char* nameNeutralGender; // 16 m_name_male_lang + // 17-18 m_facialHairCustomization[2] + // 19 m_hairCustomization + uint32 expansion; // 20 m_required_expansion + //uint32 // 21 (23 for worgens) + //uint32 // 22 4.0.0 + //uint32 // 23 4.0.0 +}; + +struct ChrPowerTypesEntry +{ + uint32 entry; // 0 + uint32 classId; // 1 + uint32 power; // 2 }; /* not used @@ -747,6 +789,7 @@ struct CreatureDisplayInfoEntry // 13 m_particleColorID // 14 m_creatureGeosetData // 15 m_objectEffectPackageID + // 16 }; struct CreatureDisplayInfoExtraEntry @@ -785,18 +828,17 @@ struct CreatureFamilyEntry uint32 petFoodMask; // 7 m_petFoodMask int32 petTalentType; // 8 m_petTalentType // 9 m_categoryEnumID - char* Name[16]; // 10-25 m_name_lang - // 26 string flags - // 27 m_iconFile + char* Name; // 10 m_name_lang + // 11 m_iconFile }; struct CreatureModelDataEntry { uint32 Id; uint32 Flags; - //char* ModelPath[16] + //char* ModelPath //uint32 Unk1; - float Scale; // Used in calculation of unit collision data + //float Scale; // Used in calculation of unit collision data //int32 Unk2 //int32 Unk3 //uint32 Unk4 @@ -824,9 +866,8 @@ struct CreatureSpellDataEntry struct CreatureTypeEntry { uint32 ID; // 0 m_ID - //char* Name[16]; // 1-16 name - // 17 string flags - //uint32 no_expirience; // 18 no exp? critters, non-combat pets, gas cloud. + //char* Name; // 1 m_name_lang + //uint32 no_expirience; // 2 m_flags no exp? critters, non-combat pets, gas cloud. }; /* not used @@ -841,43 +882,55 @@ struct CurrencyCategoryEntry struct CurrencyTypesEntry { - //uint32 ID; // 0 not used - uint32 ItemId; // 1 used as real index - //uint32 Category; // 2 may be category - uint32 BitIndex; // 3 bit index in PLAYER_FIELD_KNOWN_CURRENCIES (1 << (index-1)) + uint32 ID; // 0 not used + uint32 Category; // 1 may be category + //char* name; // 2 + //char* iconName; // 3 + //uint32 unk4; // 4 all 0 + uint32 HasSubstitution; // 5 archaeology-related (?) + uint32 SubstitutionId; // 6 + uint32 TotalCap; // 7 + uint32 WeekCap; // 8 + uint32 Flags; // 9 + //char* description; // 10 }; struct DestructibleModelDataEntry { uint32 Id; + uint32 DamagedDisplayId; //uint32 DamagedUnk1; //uint32 DamagedUnk2; - uint32 DamagedDisplayId; //uint32 DamagedUnk3; + uint32 DestroyedDisplayId; //uint32 DestroyedUnk1; //uint32 DestroyedUnk2; - uint32 DestroyedDisplayId; //uint32 DestroyedUnk3; + //uint32 DestroyedUnk4; + uint32 RebuildingDisplayId; //uint32 RebuildingUnk1; //uint32 RebuildingUnk2; - uint32 RebuildingDisplayId; //uint32 RebuildingUnk3; + //uint32 RebuildingUnk4; + uint32 SmokeDisplayId; //uint32 SmokeUnk1; //uint32 SmokeUnk2; - uint32 SmokeDisplayId; //uint32 SmokeUnk3; - //uint32 Unk4; - //uint32 Unk5; + //uint32 SmokeUnk4; + //uint32 UnkDisplayid; + //uint32 Unk6; + //uint32 Unk7; + //uint32 Unk8; }; struct DungeonEncounterEntry { uint32 id; // 0 unique id uint32 mapId; // 1 map id - uint32 difficulty; // 2 instance mode + int32 difficulty; // 2 instance mode //uint32 unk0; // 3 uint32 encounterIndex; // 4 encounter index for creating completed mask - char* encounterName[16]; // 5-20 encounter name + char* encounterName; // 5 encounter name //uint32 nameFlags; // 21 //uint32 unk1; // 22 }; @@ -897,12 +950,13 @@ struct DurabilityQualityEntry struct EmotesEntry { uint32 Id; // 0 - //char* Name; // 1, internal name - //uint32 AnimationId; // 2, ref to animationData + //char* Name; // 1, internal name + //uint32 AnimationId; // 2, ref to animationData uint32 Flags; // 3, bitmask, may be unit_flags uint32 EmoteType; // 4, Can be 0, 1 or 2 (determine how emote are shown) uint32 UnitStandState; // 5, uncomfirmed, may be enum UnitStandStateType - //uint32 SoundId; // 6, ref to soundEntries + //uint32 SoundId; // 6, ref to soundEntries + //uint32 unk7 // 7 }; struct EmotesTextEntry @@ -924,10 +978,9 @@ struct FactionEntry float spilloverRateOut; // 20 Faction outputs rep * spilloverRateOut as spillover reputation uint32 spilloverMaxRankIn; // 21 The highest rank the faction will profit from incoming spillover //uint32 spilloverRank_unk; // 22 It does not seem to be the max standing at which a faction outputs spillover ...so no idea - char* name[16]; // 23-38 m_name_lang - // 39 string flags - //char* description[16]; // 40-55 m_description_lang - // 56 string flags + char* name; // 23 m_name_lang + //char* description; // 24 m_description_lang + uint32 GroupExpansion; // 25 m_factionGroupExpansion // helpers bool CanHaveReputation() const @@ -953,6 +1006,8 @@ struct FactionTemplateEntry // helpers bool IsFriendlyTo(FactionTemplateEntry const& entry) const { + if (ID == entry.ID) + return true; if (entry.faction) { for (int i = 0; i < MAX_FACTION_RELATIONS; ++i) @@ -966,6 +1021,8 @@ struct FactionTemplateEntry } bool IsHostileTo(FactionTemplateEntry const& entry) const { + if (ID == entry.ID) + return false; if (entry.faction) { for (int i = 0; i < MAX_FACTION_RELATIONS; ++i) @@ -991,22 +1048,25 @@ struct FactionTemplateEntry struct GameObjectDisplayInfoEntry { uint32 Displayid; // 0 m_ID - char* filename; // 1 - //uint32 unk1[10]; //2-11 + char* filename; // 1 + //uint32 unk1[10]; //2-11 float minX; float minY; float minZ; float maxX; float maxY; float maxZ; - //uint32 transport; //18 + //uint32 transport; //18 }; struct GemPropertiesEntry { - uint32 ID; - uint32 spellitemenchantement; - uint32 color; + uint32 ID; // 0 m_id + uint32 spellitemenchantement; // 1 m_enchant_id + // 2 m_maxcount_inv + // 3 m_maxcount_item + uint32 color; // 4 m_type + uint32 minJewelCraftingSkill; // 5 m_minJewelCraftingSkill }; struct GlyphPropertiesEntry @@ -1014,7 +1074,7 @@ struct GlyphPropertiesEntry uint32 Id; uint32 SpellId; uint32 TypeFlags; - uint32 Unk1; // GlyphIconId (SpellIcon.dbc) + uint32 IconId; // GlyphIconId (SpellIcon.dbc) }; struct GlyphSlotEntry @@ -1031,21 +1091,25 @@ struct GlyphSlotEntry struct GtBarberShopCostBaseEntry { + //uint32 level; float cost; }; struct GtCombatRatingsEntry { + //uint32 level; float ratio; }; struct GtChanceToMeleeCritBaseEntry { + //uint32 level; float base; }; struct GtChanceToMeleeCritEntry { + //uint32 level; float ratio; }; @@ -1074,10 +1138,15 @@ struct GtOCTRegenHPEntry float ratio; }; -//struct GtOCTRegenMPEntry -//{ -// float ratio; -//}; +struct GtOCTRegenMPEntry +{ + float ratio; +}; + +struct gtOCTHpPerStaminaEntry +{ + float ratio; +}; struct GtRegenHPPerSptEntry { @@ -1089,12 +1158,33 @@ struct GtRegenMPPerSptEntry float ratio; }; +struct GtSpellScalingEntry +{ + float value; +}; + +struct GtOCTBaseHPByClassEntry +{ + float ratio; +}; + +struct GtOCTBaseMPByClassEntry +{ + float ratio; +}; + +struct GuildPerkSpellsEntry +{ + //uint32 Id; + uint32 Level; + uint32 SpellId; +}; + /* no used struct HolidayDescriptionsEntry { uint32 ID; // 0, m_holidayDescriptionID - //char* name[16] // 1-16 m_name_lang - // 17 name flags + //char* name // 1 m_name_lang }; */ @@ -1102,8 +1192,7 @@ struct HolidayDescriptionsEntry struct HolidayNamesEntry { uint32 ID; // 0, m_holidayNameID - //char* name[16] // 1-16 m_name_lang - // 17 name flags + //char* name // 1 m_name_lang }; */ @@ -1127,23 +1216,105 @@ struct HolidaysEntry //uint32 flags; // 54 m_flags (0 = Darkmoon Faire, Fishing Contest and Wotlk Launch, rest is 1) }; -struct ItemEntry +// ImportPriceArmor.dbc +struct ImportPriceArmorEntry { - uint32 ID; // 0 - uint32 Class; // 1 - uint32 SubClass; // 2 some items have strange subclasses - int32 SoundOverrideSubclass; // 3 - int32 Material; // 4 - uint32 DisplayId; // 5 - uint32 InventoryType; // 6 - uint32 Sheath; // 7 + uint32 InventoryType; // 1 Id/InventoryType + float ClothFactor; // 2 Price factor cloth + float LeatherFactor; // 3 Price factor leather + float MailFactor; // 4 Price factor mail + float PlateFactor; // 5 Price factor plate +}; + +// ImportPriceQuality.dbc +struct ImportPriceQualityEntry +{ + uint32 QualityId; // 1 Quality Id (+1?) + float Factor; // 2 Price factor +}; + +// ImportPriceShield.dbc +struct ImportPriceShieldEntry +{ + uint32 Id; // 1 Unk id (only 1 and 2) + float Factor; // 2 Price factor +}; + +// ImportPriceWeapon.dbc +struct ImportPriceWeaponEntry +{ + uint32 Id; // 1 Unk id (mainhand - 0, offhand - 1, weapon - 2, 2hweapon - 3, ranged/rangedright/relic - 4) + float Factor; // 2 Price factor +}; + +// ItemPriceBase.dbc +struct ItemPriceBaseEntry +{ + uint32 ItemLevel; // 2 Item level (1 - 1000) + float ArmorFactor; // 3 Price factor for armor + float WeaponFactor; // 4 Price factor for weapons +}; + +struct ItemReforgeEntry +{ + uint32 Id; + uint32 SourceStat; + float SourceMultiplier; + uint32 FinalStat; + float FinalMultiplier; +}; + +// common struct for: +// ItemDamageAmmo.dbc +// ItemDamageOneHand.dbc +// ItemDamageOneHandCaster.dbc +// ItemDamageRanged.dbc +// ItemDamageThrown.dbc +// ItemDamageTwoHand.dbc +// ItemDamageTwoHandCaster.dbc +// ItemDamageWand.dbc +struct ItemDamageEntry +{ + uint32 Id; // 0 item level + float DPS[7]; // 1-7 multiplier for item quality + uint32 Id2; // 8 item level +}; + +struct ItemArmorQualityEntry +{ + uint32 Id; // 0 item level + float Value[7]; // 1-7 multiplier for item quality + uint32 Id2; // 8 item level +}; + +struct ItemArmorShieldEntry +{ + uint32 Id; // 0 item level + uint32 Id2; // 1 item level + float Value[7]; // 2-8 multiplier for item quality +}; + +struct ItemArmorTotalEntry +{ + uint32 Id; // 0 item level + uint32 Id2; // 1 item level + float Value[4]; // 2-5 multiplier for armor types (cloth...plate) +}; + +// ItemClass.dbc +struct ItemClassEntry +{ + uint32 Class; // 1 item class id + //uint32 Unk; // 2 unk + //uint32 IsWeapon; // 3 1 for weapon, 0 for everything else + float PriceFactor; // 4 used to calculate certain prices + //char* Name; // class name }; struct ItemBagFamilyEntry { uint32 ID; // 0 - //char* name[16] // 1-16 m_name_lang - // // 17 name flags + //char* name; // 1 m_name_lang }; struct ItemDisplayInfoEntry @@ -1162,34 +1333,23 @@ struct ItemDisplayInfoEntry // 11 m_particleColorID }; -//struct ItemCondExtCostsEntry -//{ -// uint32 ID; -// uint32 condExtendedCost; // ItemTemplate::CondExtendedCost -// uint32 itemextendedcostentry; // ItemTemplate::ExtendedCost -// uint32 arenaseason; // arena season number(1-4) -//}; - -#define MAX_ITEM_EXTENDED_COST_REQUIREMENTS 5 - -struct ItemExtendedCostEntry +struct ItemDisenchantLootEntry { - uint32 ID; // 0 extended-cost entry id - uint32 reqhonorpoints; // 1 required honor points - uint32 reqarenapoints; // 2 required arena points - uint32 reqarenaslot; // 3 arena slot restrctions (min slot value) - uint32 reqitem[MAX_ITEM_EXTENDED_COST_REQUIREMENTS]; // 4-8 required item id - uint32 reqitemcount[MAX_ITEM_EXTENDED_COST_REQUIREMENTS]; // 9-14 required count of 1st item - uint32 reqpersonalarenarating; // 15 required personal arena rating}; + uint32 Id; + uint32 ItemClass; + int32 ItemSubClass; + uint32 ItemQuality; + uint32 MinItemLevel; + uint32 MaxItemLevel; + uint32 RequiredDisenchantSkill; }; struct ItemLimitCategoryEntry { uint32 ID; // 0 Id - //char* name[16] // 1-16 m_name_lang - // 17 name flags - uint32 maxCount; // 18, max allowed equipped as item or in gem slot - uint32 mode; // 19, 0 = have, 1 = equip (enum ItemLimitCategoryMode) + //char* name; // 1 m_name_lang + uint32 maxCount; // 2, m_quantity max allowed equipped as item or in gem slot + uint32 mode; // 3, m_flags 0 = have, 1 = equip (enum ItemLimitCategoryMode) }; #define MAX_ITEM_ENCHANTMENT_EFFECTS 3 @@ -1197,23 +1357,19 @@ struct ItemLimitCategoryEntry struct ItemRandomPropertiesEntry { uint32 ID; // 0 m_ID - //char* internalName // 1 m_Name + //char* internalName // 1 m_Name uint32 enchant_id[MAX_ITEM_ENCHANTMENT_EFFECTS]; // 2-4 m_Enchantment // 5-6 unused - char* nameSuffix[16]; // 7-22 m_name_lang - // 23 name flags + char* nameSuffix; // 7 m_name_lang }; struct ItemRandomSuffixEntry { uint32 ID; // 0 m_ID - char* nameSuffix[16]; // 1-16 m_name_lang - // 17, name flags - // 18 m_internalName - uint32 enchant_id[MAX_ITEM_ENCHANTMENT_EFFECTS]; // 19-21 m_enchantment - //uint32 unk1[2] // 22-23 unknown - uint32 prefix[MAX_ITEM_ENCHANTMENT_EFFECTS]; // 24-26 m_allocationPct - //uint32 unk2[2] // 27-28 unknown + char* nameSuffix; // 1 m_name_lang + // 2 m_internalName + uint32 enchant_id[5]; // 3-7 m_enchantment + uint32 prefix[5]; // 8-12 m_allocationPct }; #define MAX_ITEM_SET_ITEMS 10 @@ -1222,35 +1378,34 @@ struct ItemRandomSuffixEntry struct ItemSetEntry { //uint32 id // 0 m_ID - char* name[16]; // 1-16 m_name_lang - // 17 string flags, unused - uint32 itemId[MAX_ITEM_SET_ITEMS]; // 18-27 m_itemID - //uint32 unknown[7]; // 28-34 unk, all 0 - uint32 spells[MAX_ITEM_SET_SPELLS]; // 35-42 m_setSpellID - uint32 items_to_triggerspell[MAX_ITEM_SET_SPELLS]; // 43-50 m_setThreshold - uint32 required_skill_id; // 51 m_requiredSkill - uint32 required_skill_value; // 52 m_requiredSkillRank + char* name; // 1 m_name_lang + uint32 itemId[MAX_ITEM_SET_ITEMS]; // 2-18 m_itemID + uint32 spells[MAX_ITEM_SET_SPELLS]; // 19-26 m_setSpellID + uint32 items_to_triggerspell[MAX_ITEM_SET_SPELLS]; // 27-34 m_setThreshold + uint32 required_skill_id; // 35 m_requiredSkill + uint32 required_skill_value; // 36 m_requiredSkillRank }; struct LFGDungeonEntry { uint32 ID; // 0 - char* name[16]; // 1-17 Name lang - uint32 minlevel; // 18 - uint32 maxlevel; // 19 - uint32 reclevel; // 20 - uint32 recminlevel; // 21 - uint32 recmaxlevel; // 22 - int32 map; // 23 - uint32 difficulty; // 24 - uint32 flags; // 25 - uint32 type; // 26 - //uint32 unk; // 27 - //char* iconname; // 28 - uint32 expansion; // 29 - //uint32 unk4; // 30 - uint32 grouptype; // 31 - //char* desc[16]; // 32-47 Description + char* name; // 1 + uint32 minlevel; // 2 + uint32 maxlevel; // 3 + uint32 reclevel; // 4 + uint32 recminlevel; // 5 + uint32 recmaxlevel; // 6 + int32 map; // 7 + uint32 difficulty; // 8 + uint32 flags; // 9 + uint32 type; // 10 + //uint32 unk2; // 11 + //char* iconname; // 12 + uint32 expansion; // 13 + //uint32 unk4; // 14 + uint32 grouptype; // 15 + //char* desc; // 16 Description + uint32 randomCategoryId; // 17 RandomDungeonID assigned for this dungeon // Helpers uint32 Entry() const { return ID + (type << 24); } }; @@ -1308,12 +1463,25 @@ struct LockEntry //uint32 Action[MAX_LOCK_CASE]; // 25-32 m_Action }; +struct PhaseEntry +{ + uint32 ID; // 0 + char* Name; // 1 + uint32 flag; // 2 +}; + +struct PhaseGroupEntry +{ + uint32 ID; + uint32 PhaseId; + uint32 GroupId; +}; + struct MailTemplateEntry { uint32 ID; // 0 - //char* subject[16]; // 1-16 - // 17 name flags, unused - char* content[16]; // 18-33 + //char* subject; // 1 m_subject_lang + char* content; // 2 m_body_lang }; struct MapEntry @@ -1322,23 +1490,22 @@ struct MapEntry //char* internalname; // 1 unused uint32 map_type; // 2 uint32 Flags; // 3 - // 4 0 or 1 for battlegrounds (not arenas) - char* name[16]; // 5-20 - // 21 name flags, unused - uint32 linked_zone; // 22 common zone for instance and continent map - //char* hordeIntro[16]; // 23-38 text for PvP Zones - // 39 intro text flags - //char* allianceIntro[16]; // 40-55 text for PvP Zones - // 56 intro text flags - uint32 multimap_id; // 57 - //float BattlefieldMapIconScale; // 58 - int32 entrance_map; // 59 map_id of entrance map - float entrance_x; // 60 entrance x coordinate (if exist single entry) - float entrance_y; // 61 entrance y coordinate (if exist single entry) - //uint32 TimeOfDayOverride; // 62 -1, 0 and 720 - uint32 addon; // 63 (0-original maps, 1-tbc addon) - uint32 unk_time; // 64 some kind of time? - uint32 maxPlayers; // 65 max players, fallback if not present in MapDifficulty.dbc + //uint32 unk4; // 4 4.0.1 + //uint32 isPvP; // 5 m_PVP 0 or 1 for battlegrounds (not arenas) + char* name; // 6 m_MapName_lang + uint32 linked_zone; // 7 m_areaTableID + //char* hordeIntro; // 8 m_MapDescription0_lang + //char* allianceIntro; // 9 m_MapDescription1_lang + uint32 multimap_id; // 10 m_LoadingScreenID (LoadingScreens.dbc) + //float BattlefieldMapIconScale; // 11 m_minimapIconScale + int32 entrance_map; // 12 m_corpseMapID map_id of entrance map in ghost mode (continent always and in most cases = normal entrance) + float entrance_x; // 13 m_corpseX entrance x coordinate in ghost mode (in most cases = normal entrance) + float entrance_y; // 14 m_corpseY entrance y coordinate in ghost mode (in most cases = normal entrance) + //uint32 timeOfDayOverride; // 15 m_timeOfDayOverride + uint32 addon; // 16 m_expansionID + uint32 expireTime; // 17 m_raidOffset + uint32 maxPlayers; // 18 m_maxPlayers + int32 rootPhaseMap; // 19 new 4.0.0, mapid, related to phasing // Helpers uint32 Expansion() const { return addon; } @@ -1375,18 +1542,52 @@ struct MapDifficultyEntry //uint32 Id; // 0 uint32 MapId; // 1 uint32 Difficulty; // 2 (for arenas: arena slot) - char* areaTriggerText; // 3-18 text showed when transfer to map failed (missing requirements) - //uint32 textFlags; // 19 - uint32 resetTime; // 20 - uint32 maxPlayers; // 21 - //char* difficultyString; // 22 + char* areaTriggerText; // 3 m_message_lang (text showed when transfer to map failed) + uint32 resetTime; // 4, m_raidDuration in secs, 0 if no fixed reset time + uint32 maxPlayers; // 5, m_maxPlayers some heroic versions have 0 when expected same amount as in normal version + //char* difficultyString; // 6 m_difficultystring +}; + +struct MountCapabilityEntry +{ + uint32 Id; + uint32 Flags; + uint32 RequiredRidingSkill; + uint32 RequiredArea; + uint32 RequiredAura; + uint32 RequiredSpell; + uint32 SpeedModSpell; + int32 RequiredMap; +}; + +#define MAX_MOUNT_CAPABILITIES 24 + +struct MountTypeEntry +{ + uint32 Id; + uint32 MountCapability[MAX_MOUNT_CAPABILITIES]; }; struct MovieEntry { uint32 Id; // 0 index //char* filename; // 1 - //uint32 unk2; // 2 always 100 + //uint32 unk1; // 2 m_volume + //uint32 unk2; // 3 4.0.0 +}; + +struct NameGenEntry +{ + //uint32 id; + char* name; + uint32 race; + uint32 gender; +}; + +struct NumTalentsAtLevelEntry +{ + //uint32 Level; // 0 index + float Talents; // 1 talent count }; #define MAX_OVERRIDE_SPELL 10 @@ -1396,6 +1597,7 @@ struct OverrideSpellDataEntry uint32 id; // 0 uint32 spellId[MAX_OVERRIDE_SPELL]; // 1-10 //uint32 unk0; // 11 + //char* SpellBarName; // 12 }; struct PowerDisplayEntry @@ -1424,8 +1626,7 @@ struct PvPDifficultyEntry struct QuestSortEntry { uint32 id; // 0 m_ID - //char* name[16]; // 1-16 m_SortName_lang - // 17 name flags + //char* name; // 1 m_SortName_lang }; struct QuestXPEntry @@ -1454,78 +1655,23 @@ struct ScalingStatDistributionEntry uint32 Id; // 0 int32 StatMod[10]; // 1-10 uint32 Modifier[10]; // 11-20 - uint32 MaxLevel; // 21 + //uint32 unk1; // 21 + uint32 MaxLevel; // 22 m_maxlevel }; struct ScalingStatValuesEntry { - uint32 Id; // 0 - uint32 Level; // 1 - uint32 ssdMultiplier[4]; // 2-5 Multiplier for ScalingStatDistribution - uint32 armorMod[4]; // 6-9 Armor for level - uint32 dpsMod[6]; // 10-15 DPS mod for level - uint32 spellPower; // 16 spell power for level - uint32 ssdMultiplier2; // 17 there's data from 3.1 dbc ssdMultiplier[3] - uint32 ssdMultiplier3; // 18 3.3 - uint32 armorMod2[5]; // 19-23 Armor for level - - uint32 getssdMultiplier(uint32 mask) const - { - if (mask & 0x4001F) - { - if (mask & 0x00000001) return ssdMultiplier[0]; // Shoulder - if (mask & 0x00000002) return ssdMultiplier[1]; // Trinket - if (mask & 0x00000004) return ssdMultiplier[2]; // Weapon1H - if (mask & 0x00000008) return ssdMultiplier2; - if (mask & 0x00000010) return ssdMultiplier[3]; // Ranged - if (mask & 0x00040000) return ssdMultiplier3; - } - return 0; - } - - uint32 getArmorMod(uint32 mask) const - { - if (mask & 0x00F001E0) - { - if (mask & 0x00000020) return armorMod[0]; // Cloth shoulder - if (mask & 0x00000040) return armorMod[1]; // Leather shoulder - if (mask & 0x00000080) return armorMod[2]; // Mail shoulder - if (mask & 0x00000100) return armorMod[3]; // Plate shoulder - - if (mask & 0x00080000) return armorMod2[0]; // cloak - if (mask & 0x00100000) return armorMod2[1]; // cloth - if (mask & 0x00200000) return armorMod2[2]; // leather - if (mask & 0x00400000) return armorMod2[3]; // mail - if (mask & 0x00800000) return armorMod2[4]; // plate - } - return 0; - } - - uint32 getDPSMod(uint32 mask) const - { - if (mask & 0x7E00) - { - if (mask & 0x00000200) return dpsMod[0]; // Weapon 1h - if (mask & 0x00000400) return dpsMod[1]; // Weapon 2h - if (mask & 0x00000800) return dpsMod[2]; // Caster dps 1h - if (mask & 0x00001000) return dpsMod[3]; // Caster dps 2h - if (mask & 0x00002000) return dpsMod[4]; // Ranged - if (mask & 0x00004000) return dpsMod[5]; // Wand - } - return 0; - } - - uint32 getSpellBonus(uint32 mask) const - { - if (mask & 0x00008000) return spellPower; - return 0; - } + uint32 Id; // 0 + uint32 Level; // 1 + uint32 dpsMod[6]; // 2-7 DPS mod for level + uint32 Spellpower; // 8 spell power for level + uint32 StatMultiplier[5]; // 9-13 Multiplier for ScalingStatDistribution + uint32 Armor[8][4]; // 14-46 Armor for level + uint32 CloakArmor; // 47 armor for cloak - uint32 getFeralBonus(uint32 mask) const // removed in 3.2.x? - { - if (mask & 0x00010000) return 0; // not used? - return 0; - } + uint32 GetStatMultiplier(uint32 inventoryType) const; + uint32 GetArmor(uint32 inventoryType, uint32 armorType) const; + uint32 GetDPSAndDamageMultiplier(uint32 subClass, bool isCasterWeapon, float* damageMultiplier) const; }; //struct SkillLineCategoryEntry{ @@ -1540,14 +1686,11 @@ struct SkillLineEntry uint32 id; // 0 m_ID int32 categoryId; // 1 m_categoryID //uint32 skillCostID; // 2 m_skillCostsID - char* name[16]; // 3-18 m_displayName_lang - // 19 string flags - //char* description[16]; // 20-35 m_description_lang - // 36 string flags - uint32 spellIcon; // 37 m_spellIconID - //char* alternateVerb[16]; // 38-53 m_alternateVerb_lang - // 54 string flags - uint32 canLink; // 55 m_canLink (prof. with recipes + char* name; // 3 m_displayName_lang + //char* description; // 4 m_description_lang + uint32 spellIcon; // 5 m_spellIconID + //char* alternateVerb; // 6 m_alternateVerb_lang + uint32 canLink; // 7 m_canLink (prof. with recipes) }; struct SkillLineAbilityEntry @@ -1564,28 +1707,29 @@ struct SkillLineAbilityEntry uint32 AutolearnType; // 9 m_acquireMethod uint32 max_value; // 10 m_trivialSkillLineRankHigh uint32 min_value; // 11 m_trivialSkillLineRankLow - //uint32 characterPoints[2]; // 12-13 m_characterPoints[2] + uint32 character_points[2]; // 12-13 m_characterPoints }; struct SkillRaceClassInfoEntry { - //uint32 Id; // 0 - uint32 SkillId; // 1 - uint32 RaceMask; // 2 - uint32 ClassMask; // 3 - uint32 Flags; // 4 - //uint32 MinLevel; // 5 - uint32 SkillTier; // 6 - //uint32 SkillCostType; // 7 + //uint32 Id; // 0 m_ID + uint32 SkillId; // 1 m_skillID + uint32 RaceMask; // 2 m_raceMask + uint32 ClassMask; // 3 m_classMask + uint32 Flags; // 4 m_flags + //uint32 Unk; // 5 m_unk + //uint32 MinLevel; // 6 m_minLevel + uint32 SkillTier; // 7 m_skillTierID + //uint32 SkillCostType; // 8 m_skillCostIndex }; #define MAX_SKILL_STEP 16 struct SkillTiersEntry { - uint32 Id; // 0 - //uint32 StepCost[MAX_SKILL_STEP]; // 1-16 - uint32 MaxSkill[MAX_SKILL_STEP]; // 17-32 + uint32 Id; // 0 m_ID + //uint32 StepCost[MAX_SKILL_STEP]; // 1-16 m_cost + uint32 MaxSkill[MAX_SKILL_STEP]; // 17-32 m_valueMax }; struct SoundEntriesEntry @@ -1601,124 +1745,155 @@ struct SoundEntriesEntry // 26 m_minDistance // 27 m_distanceCutoff // 28 m_EAXDef - // 29 new in 3.1 + // 29 m_soundEntriesAdvancedID, new in 3.1 + //unk // 30 4.0.0 + //unk // 31 4.0.0 + //unk // 32 4.0.0 + //unk // 33 4.0.0 +}; + +// SpellEffect.dbc +struct SpellEffectEntry +{ + uint32 Id; // 0 m_ID + uint32 Effect; // 1 m_effect + float EffectValueMultiplier; // 2 m_effectAmplitude + uint32 EffectApplyAuraName; // 3 m_effectAura + uint32 EffectAmplitude; // 4 m_effectAuraPeriod + int32 EffectBasePoints; // 5 m_effectBasePoints (don't must be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints) + float EffectBonusMultiplier; // 6 m_effectBonus + float EffectDamageMultiplier; // 7 m_effectChainAmplitude + uint32 EffectChainTarget; // 8 m_effectChainTargets + int32 EffectDieSides; // 9 m_effectDieSides + uint32 EffectItemType; // 10 m_effectItemType + uint32 EffectMechanic; // 11 m_effectMechanic + int32 EffectMiscValue; // 12 m_effectMiscValue + int32 EffectMiscValueB; // 13 m_effectMiscValueB + float EffectPointsPerComboPoint; // 14 m_effectPointsPerCombo + uint32 EffectRadiusIndex; // 15 m_effectRadiusIndex - spellradius.dbc + uint32 EffectRadiusMaxIndex; // 16 4.0.0 + float EffectRealPointsPerLevel; // 17 m_effectRealPointsPerLevel + flag96 EffectSpellClassMask; // 18 19 20 m_effectSpellClassMask1(2/3), effect 0 + uint32 EffectTriggerSpell; // 21 m_effectTriggerSpell + uint32 EffectImplicitTargetA; // 22 m_implicitTargetA + uint32 EffectImplicitTargetB; // 23 m_implicitTargetB + uint32 EffectSpellId; // 24 new 4.0.0 + uint32 EffectIndex; // 25 new 4.0.0 + //uint32 Unk0 // 26 4.2.0 only 0 or 1 }; #define MAX_SPELL_EFFECTS 3 #define MAX_EFFECT_MASK 7 #define MAX_SPELL_REAGENTS 8 +// SpellAuraOptions.dbc +struct SpellAuraOptionsEntry +{ + uint32 Id; // 0 m_ID + uint32 StackAmount; // 1 m_cumulativeAura + uint32 procChance; // 2 m_procChance + uint32 procCharges; // 3 m_procCharges + uint32 procFlags; // 4 m_procTypeMask +}; + +// SpellAuraRestrictions.dbc/ +struct SpellAuraRestrictionsEntry +{ + //uint32 Id; // 0 m_ID + uint32 CasterAuraState; // 1 m_casterAuraState + uint32 TargetAuraState; // 2 m_targetAuraState + uint32 CasterAuraStateNot; // 3 m_excludeCasterAuraState + uint32 TargetAuraStateNot; // 4 m_excludeTargetAuraState + uint32 casterAuraSpell; // 5 m_casterAuraSpell + uint32 targetAuraSpell; // 6 m_targetAuraSpell + uint32 excludeCasterAuraSpell; // 7 m_excludeCasterAuraSpell + uint32 excludeTargetAuraSpell; // 8 m_excludeTargetAuraSpell +}; + +// SpellCastingRequirements.dbc +struct SpellCastingRequirementsEntry +{ + //uint32 Id; // 0 m_ID + uint32 FacingCasterFlags; // 1 m_facingCasterFlags + //uint32 MinFactionId; // 2 m_minFactionID not used + //uint32 MinReputation; // 3 m_minReputation not used + int32 AreaGroupId; // 4 m_requiredAreaGroupId + //uint32 RequiredAuraVision; // 5 m_requiredAuraVision not used + uint32 RequiresSpellFocus; // 6 m_requiresSpellFocus +}; + +#define MAX_SPELL_TOTEMS 2 + +// SpellTotems.dbc +struct SpellTotemsEntry +{ + uint32 Id; // 0 m_ID + uint32 TotemCategory[MAX_SPELL_TOTEMS]; // 1 m_requiredTotemCategoryID + uint32 Totem[MAX_SPELL_TOTEMS]; // 2 m_totem +}; + +// Spell.dbc struct SpellEntry { uint32 Id; // 0 m_ID + uint32 Attributes; // 1 m_attribute + uint32 AttributesEx; // 2 m_attributesEx + uint32 AttributesEx2; // 3 m_attributesExB + uint32 AttributesEx3; // 4 m_attributesExC + uint32 AttributesEx4; // 5 m_attributesExD + uint32 AttributesEx5; // 6 m_attributesExE + uint32 AttributesEx6; // 7 m_attributesExF + uint32 AttributesEx7; // 8 m_attributesExG + uint32 AttributesEx8; // 9 m_attributesExH + uint32 AttributesEx9; // 10 m_attributesExI + uint32 AttributesEx10; // 11 m_attributesExJ + uint32 CastingTimeIndex; // 12 m_castingTimeIndex + uint32 DurationIndex; // 13 m_durationIndex + uint32 powerType; // 14 m_powerType + uint32 rangeIndex; // 15 m_rangeIndex + float speed; // 16 m_speed + uint32 SpellVisual[2]; // 17-18 m_spellVisualID + uint32 SpellIconID; // 19 m_spellIconID + uint32 activeIconID; // 20 m_activeIconID + char* SpellName; // 21 m_name_lang + char* Rank; // 22 m_nameSubtext_lang + //char* Description; // 23 m_description_lang not used + //char* ToolTip; // 24 m_auraDescription_lang not used + uint32 SchoolMask; // 25 m_schoolMask + uint32 runeCostID; // 26 m_runeCostID + //uint32 spellMissileID; // 27 m_spellMissileID not used + //uint32 spellDescriptionVariableID; // 28 m_spellDescriptionVariableID, 3.2.0 + uint32 SpellDifficultyId; // 29 m_spellDifficultyID - id from SpellDifficulty.dbc + float SpellCoef; // 30 + uint32 SpellScalingId; // 31 SpellScaling.dbc + uint32 SpellAuraOptionsId; // 32 SpellAuraOptions.dbc + uint32 SpellAuraRestrictionsId; // 33 SpellAuraRestrictions.dbc + uint32 SpellCastingRequirementsId; // 34 SpellCastingRequirements.dbc + uint32 SpellCategoriesId; // 35 SpellCategories.dbc + uint32 SpellClassOptionsId; // 36 SpellClassOptions.dbc + uint32 SpellCooldownsId; // 37 SpellCooldowns.dbc + //uint32 unkIndex7; // 38 all zeros... + uint32 SpellEquippedItemsId; // 39 SpellEquippedItems.dbc + uint32 SpellInterruptsId; // 40 SpellInterrupts.dbc + uint32 SpellLevelsId; // 41 SpellLevels.dbc + uint32 SpellPowerId; // 42 SpellPower.dbc + uint32 SpellReagentsId; // 43 SpellReagents.dbc + uint32 SpellShapeshiftId; // 44 SpellShapeshift.dbc + uint32 SpellTargetRestrictionsId; // 45 SpellTargetRestrictions.dbc + uint32 SpellTotemsId; // 46 SpellTotems.dbc + //uint32 ResearchProject; // 47 ResearchProject.dbc +}; + +// SpellCategories.dbc +struct SpellCategoriesEntry +{ + //uint32 Id; // 0 m_ID uint32 Category; // 1 m_category + uint32 DmgClass; // 153 m_defenseType uint32 Dispel; // 2 m_dispelType uint32 Mechanic; // 3 m_mechanic - uint32 Attributes; // 4 m_attributes - uint32 AttributesEx; // 5 m_attributesEx - uint32 AttributesEx2; // 6 m_attributesExB - uint32 AttributesEx3; // 7 m_attributesExC - uint32 AttributesEx4; // 8 m_attributesExD - uint32 AttributesEx5; // 9 m_attributesExE - uint32 AttributesEx6; // 10 m_attributesExF - uint32 AttributesEx7; // 11 m_attributesExG - uint32 Stances; // 12 m_shapeshiftMask - // uint32 unk_320_2; // 13 3.2.0 - uint32 StancesNot; // 14 m_shapeshiftExclude - // uint32 unk_320_3; // 15 3.2.0 - uint32 Targets; // 16 m_targets - uint32 TargetCreatureType; // 17 m_targetCreatureType - uint32 RequiresSpellFocus; // 18 m_requiresSpellFocus - uint32 FacingCasterFlags; // 19 m_facingCasterFlags - uint32 CasterAuraState; // 20 m_casterAuraState - uint32 TargetAuraState; // 21 m_targetAuraState - uint32 CasterAuraStateNot; // 22 m_excludeCasterAuraState - uint32 TargetAuraStateNot; // 23 m_excludeTargetAuraState - uint32 casterAuraSpell; // 24 m_casterAuraSpell - uint32 targetAuraSpell; // 25 m_targetAuraSpell - uint32 excludeCasterAuraSpell; // 26 m_excludeCasterAuraSpell - uint32 excludeTargetAuraSpell; // 27 m_excludeTargetAuraSpell - uint32 CastingTimeIndex; // 28 m_castingTimeIndex - uint32 RecoveryTime; // 29 m_recoveryTime - uint32 CategoryRecoveryTime; // 30 m_categoryRecoveryTime - uint32 InterruptFlags; // 31 m_interruptFlags - uint32 AuraInterruptFlags; // 32 m_auraInterruptFlags - uint32 ChannelInterruptFlags; // 33 m_channelInterruptFlags - uint32 procFlags; // 34 m_procTypeMask - uint32 procChance; // 35 m_procChance - uint32 procCharges; // 36 m_procCharges - uint32 maxLevel; // 37 m_maxLevel - uint32 baseLevel; // 38 m_baseLevel - uint32 spellLevel; // 39 m_spellLevel - uint32 DurationIndex; // 40 m_durationIndex - uint32 powerType; // 41 m_powerType - uint32 manaCost; // 42 m_manaCost - uint32 manaCostPerlevel; // 43 m_manaCostPerLevel - uint32 manaPerSecond; // 44 m_manaPerSecond - uint32 manaPerSecondPerLevel; // 45 m_manaPerSecondPerLeve - uint32 rangeIndex; // 46 m_rangeIndex - float speed; // 47 m_speed - //uint32 modalNextSpell; // 48 m_modalNextSpell not used - uint32 StackAmount; // 49 m_cumulativeAura - uint32 Totem[2]; // 50-51 m_totem - int32 Reagent[MAX_SPELL_REAGENTS]; // 52-59 m_reagent - uint32 ReagentCount[MAX_SPELL_REAGENTS]; // 60-67 m_reagentCount - int32 EquippedItemClass; // 68 m_equippedItemClass (value) - int32 EquippedItemSubClassMask; // 69 m_equippedItemSubclass (mask) - int32 EquippedItemInventoryTypeMask; // 70 m_equippedItemInvTypes (mask) - uint32 Effect[MAX_SPELL_EFFECTS]; // 71-73 m_effect - int32 EffectDieSides[MAX_SPELL_EFFECTS]; // 74-76 m_effectDieSides - float EffectRealPointsPerLevel[MAX_SPELL_EFFECTS]; // 77-79 m_effectRealPointsPerLevel - int32 EffectBasePoints[MAX_SPELL_EFFECTS]; // 80-82 m_effectBasePoints (must not be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints) - uint32 EffectMechanic[MAX_SPELL_EFFECTS]; // 83-85 m_effectMechanic - uint32 EffectImplicitTargetA[MAX_SPELL_EFFECTS]; // 86-88 m_implicitTargetA - uint32 EffectImplicitTargetB[MAX_SPELL_EFFECTS]; // 89-91 m_implicitTargetB - uint32 EffectRadiusIndex[MAX_SPELL_EFFECTS]; // 92-94 m_effectRadiusIndex - spellradius.dbc - uint32 EffectApplyAuraName[MAX_SPELL_EFFECTS]; // 95-97 m_effectAura - uint32 EffectAmplitude[MAX_SPELL_EFFECTS]; // 98-100 m_effectAuraPeriod - float EffectValueMultiplier[MAX_SPELL_EFFECTS]; // 101-103 - uint32 EffectChainTarget[MAX_SPELL_EFFECTS]; // 104-106 m_effectChainTargets - uint32 EffectItemType[MAX_SPELL_EFFECTS]; // 107-109 m_effectItemType - int32 EffectMiscValue[MAX_SPELL_EFFECTS]; // 110-112 m_effectMiscValue - int32 EffectMiscValueB[MAX_SPELL_EFFECTS]; // 113-115 m_effectMiscValueB - uint32 EffectTriggerSpell[MAX_SPELL_EFFECTS]; // 116-118 m_effectTriggerSpell - float EffectPointsPerComboPoint[MAX_SPELL_EFFECTS]; // 119-121 m_effectPointsPerCombo - flag96 EffectSpellClassMask[MAX_SPELL_EFFECTS]; // 122-130 - uint32 SpellVisual[2]; // 131-132 m_spellVisualID - uint32 SpellIconID; // 133 m_spellIconID - uint32 activeIconID; // 134 m_activeIconID - //uint32 spellPriority; // 135 not used - char* SpellName[16]; // 136-151 m_name_lang - //uint32 SpellNameFlag; // 152 not used - char* Rank[16]; // 153-168 m_nameSubtext_lang - //uint32 RankFlags; // 169 not used - //char* Description[16]; // 170-185 m_description_lang not used - //uint32 DescriptionFlags; // 186 not used - //char* ToolTip[16]; // 187-202 m_auraDescription_lang not used - //uint32 ToolTipFlags; // 203 not used - uint32 ManaCostPercentage; // 204 m_manaCostPct - uint32 StartRecoveryCategory; // 205 m_startRecoveryCategory - uint32 StartRecoveryTime; // 206 m_startRecoveryTime - uint32 MaxTargetLevel; // 207 m_maxTargetLevel - uint32 SpellFamilyName; // 208 m_spellClassSet - flag96 SpellFamilyFlags; // 209-211 - uint32 MaxAffectedTargets; // 212 m_maxTargets - uint32 DmgClass; // 213 m_defenseType - uint32 PreventionType; // 214 m_preventionType - //uint32 StanceBarOrder; // 215 m_stanceBarOrder not used - float EffectDamageMultiplier[MAX_SPELL_EFFECTS]; // 216-218 m_effectChainAmplitude - //uint32 MinFactionId; // 219 m_minFactionID not used - //uint32 MinReputation; // 220 m_minReputation not used - //uint32 RequiredAuraVision; // 221 m_requiredAuraVision not used - uint32 TotemCategory[2]; // 222-223 m_requiredTotemCategoryID - int32 AreaGroupId; // 224 m_requiredAreaGroupId - uint32 SchoolMask; // 225 m_schoolMask - uint32 runeCostID; // 226 m_runeCostID - //uint32 spellMissileID; // 227 m_spellMissileID not used - //uint32 PowerDisplayId; // 228 PowerDisplay.dbc, new in 3.1 - float EffectBonusMultiplier[MAX_SPELL_EFFECTS]; // 229-231 3.2.0 - //uint32 spellDescriptionVariableID; // 232 3.2.0 - //uint32 SpellDifficultyId; // 233 3.3.0 + uint32 PreventionType; // 154 m_preventionType + uint32 StartRecoveryCategory; // 145 m_startRecoveryCategory }; typedef std::set<uint32> SpellCategorySet; @@ -1738,6 +1913,8 @@ struct SpellCategoryEntry { uint32 Id; uint32 Flags; + // uint32 unk; + // char* Name; }; struct SpellDifficultyEntry @@ -1749,8 +1926,7 @@ struct SpellDifficultyEntry struct SpellFocusObjectEntry { uint32 ID; // 0 - //char* Name[16]; // 1-15 unused - // 16 string flags, unused + //char* Name; // 1 m_name_lang }; struct SpellRadiusEntry @@ -1767,12 +1943,71 @@ struct SpellRangeEntry float minRangeHostile; float minRangeFriend; float maxRangeHostile; - float maxRangeFriend; + float maxRangeFriend; //friend means unattackable unit here uint32 type; - //char* Name[16]; // 7-23 unused - // 24 string flags, unused - //char* Name2[16]; // 25-40 unused - // 41 string flags, unused + //char* Name; // 6-21 m_displayName_lang + //char* ShortName; // 23-38 m_displayNameShort_lang +}; + +// SpellEquippedItems.dbc +struct SpellEquippedItemsEntry +{ + //uint32 Id; // 0 m_ID + int32 EquippedItemClass; // 70 m_equippedItemClass (value) + int32 EquippedItemInventoryTypeMask; // 72 m_equippedItemInvTypes (mask) + int32 EquippedItemSubClassMask; // 71 m_equippedItemSubclass (mask) +}; + +// SpellCooldowns.dbc +struct SpellCooldownsEntry +{ + //uint32 Id; // 0 m_ID + uint32 CategoryRecoveryTime; // 31 m_categoryRecoveryTime + uint32 RecoveryTime; // 30 m_recoveryTime + uint32 StartRecoveryTime; // 146 m_startRecoveryTime +}; + +// SpellClassOptions.dbc +struct SpellClassOptionsEntry +{ + //uint32 Id; // 0 m_ID + //uint32 modalNextSpell; // 1 m_modalNextSpell not used + flag96 SpellFamilyFlags; // 2-4 + uint32 SpellFamilyName; // 5 m_spellClassSet + //char* Description; // 6 4.0.0 +}; + +// SpellInterrupts.dbc +struct SpellInterruptsEntry +{ + //uint32 Id; // 0 m_ID + uint32 AuraInterruptFlags; // 1 m_auraInterruptFlags + //uint32 // 2 4.0.0 + uint32 ChannelInterruptFlags; // 3 m_channelInterruptFlags + //uint32 // 4 4.0.0 + uint32 InterruptFlags; // 5 m_interruptFlags +}; + +// SpellLevels.dbc +struct SpellLevelsEntry +{ + //uint32 Id; // 0 m_ID + uint32 baseLevel; // 1 m_baseLevel + uint32 maxLevel; // 2 m_maxLevel + uint32 spellLevel; // 3 m_spellLevel +}; + +// SpellPower.dbc +struct SpellPowerEntry +{ + //uint32 Id; // 0 m_ID + uint32 manaCost; // 1 m_manaCost + uint32 manaCostPerlevel; // 2 m_manaCostPerLevel + uint32 ManaCostPercentage; // 3 m_manaCostPct + uint32 manaPerSecond; // 4 m_manaPerSecond + uint32 manaPerSecondPerLevel; // 5 m_manaPerSecondPerLevel + //uint32 PowerDisplayId; // 6 m_powerDisplayID - id from PowerDisplay.dbc, new in 3.1 + float ManaCostPercentageFloat; // 7 4.3.0 }; struct SpellRuneCostEntry @@ -1787,21 +2022,67 @@ struct SpellRuneCostEntry #define MAX_SHAPESHIFT_SPELLS 8 -struct SpellShapeshiftEntry +struct SpellShapeshiftFormEntry { uint32 ID; // 0 //uint32 buttonPosition; // 1 unused - //char* Name[16]; // 2-17 unused - //uint32 NameFlags; // 18 unused - uint32 flags1; // 19 - int32 creatureType; // 20 <= 0 humanoid, other normal creature types - //uint32 unk1; // 21 unused - uint32 attackSpeed; // 22 - uint32 modelID_A; // 23 alliance modelid - uint32 modelID_H; // 24 horde modelid (only one form) - //uint32 unk3; // 25 unused - //uint32 unk4; // 26 unused - uint32 stanceSpell[MAX_SHAPESHIFT_SPELLS]; // 27 - 34 unused + //char* Name; // 2 unused + uint32 flags1; // 3 + int32 creatureType; // 4 <=0 humanoid, other normal creature types + //uint32 spellIcon; // 5 unused, related to next field + uint32 attackSpeed; // 6 + // Models changed, 0 is main model, the rest 3 are unused. + uint32 modelID_A; // 7 alliance modelid (0 means no model) + uint32 modelID_H; // 8 horde modelid (but only for one form) + //uint32 unk3; // 9 unused always 0 + //uint32 unk4; // 10 unused always 0 + uint32 stanceSpell[MAX_SHAPESHIFT_SPELLS]; // 11-18 spells which appear in the bar after shapeshifting + //uint32 unk5; // 19 + //uint32 unk6; // 20 +}; + +// SpellShapeshift.dbc +struct SpellShapeshiftEntry +{ + uint32 Id; // 0 - m_ID + uint32 StancesNot; // 3 - m_shapeshiftExclude + // uint32 unk_320_2; // 2 - 3.2.0 + uint32 Stances; // 1 - m_shapeshiftMask + // uint32 unk_320_3; // 4 - 3.2.0 + // uint32 StanceBarOrder; // 5 - m_stanceBarOrder not used +}; + +// SpellTargetRestrictions.dbc +struct SpellTargetRestrictionsEntry +{ + uint32 Id; // 0 m_ID + uint32 MaxAffectedTargets; // 1 m_maxTargets + uint32 MaxTargetLevel; // 2 m_maxTargetLevel + uint32 TargetCreatureType; // 3 m_targetCreatureType + uint32 Targets; // 4 m_targets +}; + +// SpellReagents.dbc +struct SpellReagentsEntry +{ + //uint32 Id; // 0 m_ID + int32 Reagent[MAX_SPELL_REAGENTS]; // 54-61 m_reagent + uint32 ReagentCount[MAX_SPELL_REAGENTS]; // 62-69 m_reagentCount +}; + +// SpellScaling.dbc +struct SpellScalingEntry +{ + //uint32 Id; // 0 m_ID + int32 CastTimeMin; // 1 + int32 CastTimeMax; // 2 + int32 CastTimeMaxLevel; // 3 + int32 ScalingClass; // 4 (index * 100) + charLevel - 1 => gtSpellScaling.dbc + float Multiplier[3]; // 5-7 + float RandomMultiplier[3]; // 8-10 + float OtherMultiplier[3]; // 11-13 + float CoefBase; // 14 some coefficient, mostly 1.0f + int32 CoefLevelBase; // 15 some level }; struct SpellDurationEntry @@ -1818,15 +2099,15 @@ struct SpellItemEnchantmentEntry uint32 amount[MAX_ITEM_ENCHANTMENT_EFFECTS]; // 5-7 m_effectPointsMin[MAX_ITEM_ENCHANTMENT_EFFECTS] //uint32 amount2[MAX_ITEM_ENCHANTMENT_EFFECTS] // 8-10 m_effectPointsMax[MAX_ITEM_ENCHANTMENT_EFFECTS] uint32 spellid[MAX_ITEM_ENCHANTMENT_EFFECTS]; // 11-13 m_effectArg[MAX_ITEM_ENCHANTMENT_EFFECTS] - char* description[16]; // 14-29 m_name_lang[16] - //uint32 descriptionFlags; // 30 name flags - uint32 aura_id; // 31 m_itemVisual - uint32 slot; // 32 m_flags - uint32 GemID; // 33 m_src_itemID - uint32 EnchantmentCondition; // 34 m_condition_id - uint32 requiredSkill; // 35 m_requiredSkillID - uint32 requiredSkillValue; // 36 m_requiredSkillRank - uint32 requiredLevel; // 37 m_requiredLevel + char* description; // 14 m_name_lang + uint32 aura_id; // 15 m_itemVisual + uint32 slot; // 16 m_flags + uint32 GemID; // 17 m_src_itemID + uint32 EnchantmentCondition; // 18 m_condition_id + uint32 requiredSkill; // 19 m_requiredSkillID + uint32 requiredSkillValue; // 20 m_requiredSkillRank + uint32 requiredLevel; // 21 new in 3.1 + // 22 new in 3.1 }; struct SpellItemEnchantmentConditionEntry @@ -1852,7 +2133,7 @@ struct SummonPropertiesEntry uint32 Category; // 1, 0 - can't be controlled?, 1 - something guardian?, 2 - pet?, 3 - something controllable?, 4 - taxi/mount? uint32 Faction; // 2, 14 rows > 0 uint32 Type; // 3, see enum - uint32 Slot; // 4, 0-6 + int32 Slot; // 4, 0-6 uint32 Flags; // 5 }; @@ -1867,27 +2148,37 @@ struct TalentEntry uint32 Row; // 2 uint32 Col; // 3 uint32 RankID[MAX_TALENT_RANK]; // 4-8 - // 9-12 not used, always 0, maybe not used high ranks - uint32 DependsOn; // 13 index in Talent.dbc (TalentEntry) - // 14-15 not used - uint32 DependsOnRank; // 16 - // 17-18 not used - //uint32 needAddInSpellBook; // 19 also need disable higest ranks on reset talent tree - //uint32 unk2; // 20, all 0 - //uint64 allowForPet; // 21 its a 64 bit mask for pet 1<<m_categoryEnumID in CreatureFamily.dbc + uint32 DependsOn; // 9 m_prereqTalent (Talent.dbc) + // 10-11 part of prev field + uint32 DependsOnRank; // 12 m_prereqRank + // 13-14 part of prev field + //uint32 needAddInSpellBook; // 15 m_flags also need disable higest ranks on reset talent tree + //uint32 unk2; // 16 m_requiredSpellID + //uint64 allowForPet; // 17 m_categoryMask its a 64 bit mask for pet 1<<m_categoryEnumID in CreatureFamily.dbc }; +#define MAX_MASTERY_SPELLS 2 + struct TalentTabEntry { uint32 TalentTabID; // 0 - //char* name[16]; // 1-16, unused - //uint32 nameFlags; // 17, unused - //unit32 spellicon; // 18 - // 19 not used - uint32 ClassMask; // 20 - uint32 petTalentMask; // 21 - uint32 tabpage; // 22 - //char* internalname; // 23 + //char* name; // 1 m_name_lang + //unit32 spellicon; // 2 m_spellIconID + uint32 ClassMask; // 3 m_classMask + uint32 petTalentMask; // 4 m_petTalentMask + uint32 tabpage; // 5 m_orderIndex + //char* internalname; // 6 m_backgroundFile + //char* description; // 7 + //uint32 rolesMask; // 8 4.0.0 + uint32 MasterySpellId[MAX_MASTERY_SPELLS]; // 9-10 passive mastery bonus spells? +}; + +struct TalentTreePrimarySpellsEntry +{ + //uint32 Id; // 0 index + uint32 TalentTree; // 1 entry from TalentTab.dbc + uint32 SpellId; // 2 spell id to learn + //uint32 Flags; // 3 some kind of flags }; struct TaxiNodesEntry @@ -1897,9 +2188,9 @@ struct TaxiNodesEntry float x; // 2 m_x float y; // 3 m_y float z; // 4 m_z - char* name[16]; // 5-21 m_Name_lang - // 22 string flags - uint32 MountCreatureID[2]; // 23-24 m_MountCreatureID[2] + char* name; // 5 m_Name_lang + uint32 MountCreatureID[2]; // 6-7 m_MountCreatureID[2] + uint32 Flags; // 8 m_Flags }; struct TaxiPathEntry @@ -1925,19 +2216,33 @@ struct TaxiPathNodeEntry uint32 departureEventID; // 10 m_departureEventID }; -struct TeamContributionPointsEntry +struct TotemCategoryEntry { - //uint32 entry; // 0 - float value; // 1 (???) + uint32 ID; // 0 + //char* name; // 1 m_name_lang + uint32 categoryType; // 2 m_totemCategoryType (one for specialization) + uint32 categoryMask; // 3 m_totemCategoryMask (compatibility mask for same type: different for totems, compatible from high to low for rods) }; -struct TotemCategoryEntry +struct UnitPowerBarEntry { - uint32 ID; // 0 - //char* name[16]; // 1-16 - // 17 string flags, unused - uint32 categoryType; // 18 (one for specialization) - uint32 categoryMask; // 19 (compatibility mask for same type: different for totems, compatible from high to low for rods) + uint32 Id; + uint32 MinPower; + uint32 MaxPower; + //uint32 Unk0; + //uint32 Unk1; + //float Unk2; + //float Unk3; + //uint32 BarType; + //uint32 TextureFile[6]; + //uint32 Unk4[6]; + //uint32 DisplayFlags; + //char* PowerName; + //char* CostString; + //char* EmptyMessage; + //char* Tooltip; + //float StartInset; + //float EndInset; }; struct TransportAnimationEntry @@ -1989,9 +2294,9 @@ struct VehicleEntry float m_msslTrgtArcRepeat; // 25 float m_msslTrgtArcWidth; // 26 float m_msslTrgtImpactRadius[2]; // 27-28 - char* m_msslTrgtArcTexture; // 29 - char* m_msslTrgtImpactTexture; // 30 - char* m_msslTrgtImpactModel[2]; // 31-32 + char* m_msslTrgtArcTexture; // 29 + char* m_msslTrgtImpactTexture; // 30 + char* m_msslTrgtImpactModel[2]; // 31-32 float m_cameraYawOffset; // 33 uint32 m_uiLocomotionType; // 34 float m_msslTrgtImpactTexRadius; // 35 @@ -2072,8 +2377,10 @@ struct WMOAreaTableEntry //uint32 field8; uint32 Flags; // 9 used for indoor/outdoor determination uint32 areaId; // 10 link to AreaTableEntry.ID - //char *Name[16]; - //uint32 nameFlags; + //char *Name; // 11 m_AreaName_lang + //uint32 field12; // 12 + //uint32 field13; // 13 + //uint32 field14; // 14 }; struct WorldMapAreaEntry @@ -2089,6 +2396,9 @@ struct WorldMapAreaEntry int32 virtual_map_id; // 8 -1 (map_id have correct map) other: virtual map where zone show (map_id - where zone in fact internally) // int32 dungeonMap_id; // 9 pointer to DungeonMap.dbc (owerride x1, x2, y1, y2 coordinates) // uint32 parentMapID; // 10 + + // uint32 minRecommendedLevel; // 12 Minimum recommended level displayed on world map + // uint32 maxRecommendedLevel; // 13 Maximum recommended level displayed on world map }; #define MAX_WORLD_MAP_OVERLAY_AREA_IDX 4 @@ -2098,9 +2408,15 @@ struct WorldMapOverlayEntry uint32 ID; // 0 //uint32 worldMapAreaId; // 1 idx in WorldMapArea.dbc uint32 areatableID[MAX_WORLD_MAP_OVERLAY_AREA_IDX]; // 2-5 - // 6-7 always 0, possible part of areatableID[] - //char* internal_name // 8 - // 9-16 some ints + //char* internal_name // 6 m_textureName + // 7 m_textureWidth + // 8 m_textureHeight + // 9 m_offsetX + // 10 m_offsetY + // 11 m_hitRectTop + // 12 m_hitRectLeft + // 13 m_hitRectBottom + // 14 m_hitRectRight }; struct WorldSafeLocsEntry @@ -2110,8 +2426,7 @@ struct WorldSafeLocsEntry float x; // 2 float y; // 3 float z; // 4 - //char* name[16] // 5-20 name, unused - // 21 name flags, unused + //char* name; // 5 m_AreaName_lang }; /* @@ -2157,6 +2472,13 @@ struct WorldStateUI #pragma pack(pop) #endif +struct VectorArray +{ + std::vector<std::string> stringVectorArray[2]; +}; + +typedef std::map<uint32, VectorArray> NameGenVectorArraysMap; + // Structures not used for casting to loaded DBC data and not required then packing struct MapDifficulty { @@ -2201,7 +2523,8 @@ struct TaxiPathNodePtr typedef Path<TaxiPathNodePtr, TaxiPathNodeEntry const> TaxiPathNodeList; typedef std::vector<TaxiPathNodeList> TaxiPathNodesByPath; -#define TaxiMaskSize 14 -typedef uint32 TaxiMask[TaxiMaskSize]; -#endif +#define TaxiMaskSize 114 +typedef uint8 TaxiMask[TaxiMaskSize]; +typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer; +#endif diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index a90cc48c5af..83f18050710 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -19,120 +19,165 @@ #ifndef TRINITY_DBCSFRM_H #define TRINITY_DBCSFRM_H -char const Achievementfmt[] = "niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii"; -const std::string CustomAchievementfmt = "pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp"; +// x - skip<uint32>, X - skip<uint8>, s - char*, f - float, i - uint32, b - uint8, d - index (not included) +// n - index (included), l - bool, p - field present in sql dbc, a - field absent in sql dbc + +char const Achievementfmt[] = "niixsxiixixxii"; +const std::string CustomAchievementfmt = "pppaaaapapaapp"; const std::string CustomAchievementIndex = "ID"; -char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix"; -char const AreaTableEntryfmt[] = "iiinixxxxxissssssssssssssssxiiiiixxx"; +char const AchievementCriteriafmt[] = "niiiliiiisiiiiixxiiiiii"; +char const AreaTableEntryfmt[] = "iiinixxxxxisiiiiiffixxxxxx"; char const AreaGroupEntryfmt[] = "niiiiiii"; -char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix"; -char const AreaTriggerEntryfmt[] = "niffffffff"; -char const AuctionHouseEntryfmt[] = "niiixxxxxxxxxxxxxxxxx"; +char const AreaPOIEntryfmt[] = "niiiiiiiiiiiffixixxixx"; +char const AreaTriggerEntryfmt[] = "nifffxxxfffff"; +char const ArmorLocationfmt[] = "nfffff"; +char const AuctionHouseEntryfmt[] = "niiix"; char const BankBagSlotPricesEntryfmt[] = "ni"; char const BannedAddOnsfmt[] = "nxxxxxxxxxx"; -char const BarberShopStyleEntryfmt[] = "nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii"; -char const BattlemasterListEntryfmt[] = "niiiiiiiiixssssssssssssssssxiixx"; -char const CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -char const CharTitlesEntryfmt[] = "nxssssssssssssssssxssssssssssssssssxi"; -char const ChatChannelsEntryfmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxx"; -char const ChrClassesEntryfmt[] = "nxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii"; -char const ChrRacesEntryfmt[] = "niixiixixxxxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; +char const BarberShopStyleEntryfmt[] = "nixxxiii"; +char const BattlemasterListEntryfmt[] = "niiiiiiiiixsiiiixxxx"; +char const CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxii"; +char const CharTitlesEntryfmt[] = "nxssix"; +char const ChatChannelsEntryfmt[] = "nixsx"; +char const ChrClassesEntryfmt[] = "nixsxxxixiiiii"; +char const ChrRacesEntryfmt[] = "niixiixixxxxixsxxxxxixxx"; +char const ChrClassesXPowerTypesfmt[] = "nii"; char const CinematicSequencesEntryfmt[] = "nxxxxxxxxx"; -char const CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxx"; +char const CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxxx"; char const CreatureDisplayInfoExtrafmt[] = "diixxxxxxxxxxxxxxxxxx"; -char const CreatureFamilyfmt[] = "nfifiiiiixssssssssssssssssxx"; -char const CreatureModelDatafmt[] = "nixxfxxxxxxxxxxffxxxxxxxxxxx"; +char const CreatureModelDatafmt[] = "nixxxxxxxxxxxxffxxxxxxxxxxxxxxx"; +char const CreatureFamilyfmt[] = "nfifiiiiixsx"; char const CreatureSpellDatafmt[] = "niiiixxxx"; -char const CreatureTypefmt[] = "nxxxxxxxxxxxxxxxxxx"; -char const CurrencyTypesfmt[] = "xnxi"; -char const DestructibleModelDatafmt[] = "nxxixxxixxxixxxixxx"; -char const DungeonEncounterfmt[] = "niixissssssssssssssssxx"; +char const CreatureTypefmt[] = "nxx"; +char const CurrencyTypesfmt[] = "nixxxiiiiix"; +char const DestructibleModelDatafmt[] = "ixxixxxixxxixxxixxxxxxxx"; +char const DungeonEncounterfmt[] = "iiixisxx"; char const DurabilityCostsfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; char const DurabilityQualityfmt[] = "nf"; -char const EmotesEntryfmt[] = "nxxiiix"; +char const EmotesEntryfmt[] = "nxxiiixx"; char const EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx"; -char const FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx"; +char const FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixsxi"; char const FactionTemplateEntryfmt[] = "niiiiiiiiiiiii"; -char const GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffx"; -char const GemPropertiesEntryfmt[] = "nixxi"; +char const GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffxxx"; +char const GemPropertiesEntryfmt[] = "nixxii"; char const GlyphPropertiesfmt[] = "niii"; char const GlyphSlotfmt[] = "nii"; -char const GtBarberShopCostBasefmt[] = "f"; -char const GtCombatRatingsfmt[] = "f"; -char const GtChanceToMeleeCritBasefmt[] = "f"; -char const GtChanceToMeleeCritfmt[] = "f"; -char const GtChanceToSpellCritBasefmt[] = "f"; -char const GtChanceToSpellCritfmt[] = "f"; -char const GtNPCManaCostScalerfmt[] = "f"; +char const GtBarberShopCostBasefmt[] = "xf"; +char const GtCombatRatingsfmt[] = "xf"; +char const GtOCTHpPerStaminafmt[] = "df"; +char const GtChanceToMeleeCritBasefmt[] = "xf"; +char const GtChanceToMeleeCritfmt[] = "xf"; +char const GtChanceToSpellCritBasefmt[] = "xf"; +char const GtChanceToSpellCritfmt[] = "xf"; +char const GtNPCManaCostScalerfmt[] = "xf"; char const GtOCTClassCombatRatingScalarfmt[] = "df"; char const GtOCTRegenHPfmt[] = "f"; //char const GtOCTRegenMPfmt[] = "f"; -char const GtRegenHPPerSptfmt[] = "f"; -char const GtRegenMPPerSptfmt[] = "f"; +char const GtRegenMPPerSptfmt[] = "xf"; +char const GtSpellScalingfmt[] = "df"; +char const GtOCTBaseHPByClassfmt[] = "df"; +char const GtOCTBaseMPByClassfmt[] = "df"; +char const GuildPerkSpellsfmt[] = "dii"; char const Holidaysfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix"; -char const Itemfmt[] = "niiiiiii"; -char const ItemBagFamilyfmt[] = "nxxxxxxxxxxxxxxxxx"; +char const ImportPriceArmorfmt[] = "nffff"; +char const ImportPriceQualityfmt[] = "nf"; +char const ImportPriceShieldfmt[] = "nf"; +char const ImportPriceWeaponfmt[] = "nf"; +char const ItemPriceBasefmt[] = "diff"; +char const ItemReforgefmt[] = "nifif"; +char const ItemBagFamilyfmt[] = "nx"; +char const ItemArmorQualityfmt[] = "nfffffffi"; +char const ItemArmorShieldfmt[] = "nifffffff"; +char const ItemArmorTotalfmt[] = "niffff"; +char const ItemClassfmt[] = "dixxfx"; +char const ItemDamagefmt[] = "nfffffffi"; +char const ItemDisenchantLootfmt[] = "niiiiii"; //char const ItemDisplayTemplateEntryfmt[] = "nxxxxxxxxxxixxxxxxxxxxx"; -//char const ItemCondExtCostsEntryfmt[] = "xiii"; -char const ItemExtendedCostEntryfmt[] = "niiiiiiiiiiiiiix"; -char const ItemLimitCategoryEntryfmt[] = "nxxxxxxxxxxxxxxxxxii"; -char const ItemRandomPropertiesfmt[] = "nxiiixxssssssssssssssssx"; -char const ItemRandomSuffixfmt[] = "nssssssssssssssssxxiiixxiiixx"; -char const ItemSetEntryfmt[] = "dssssssssssssssssxiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii"; -char const LFGDungeonEntryfmt[] = "nssssssssssssssssxiiiiiiiiixxixixxxxxxxxxxxxxxxxx"; +char const ItemLimitCategoryEntryfmt[] = "nxii"; +char const ItemRandomPropertiesfmt[] = "nxiiixxs"; +char const ItemRandomSuffixfmt[] = "nsxiiiiiiiiii"; +char const ItemSetEntryfmt[] = "dsiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii"; +char const LFGDungeonEntryfmt[] = "nsiiiiiiiiixxixixixxx"; char const LightEntryfmt[] = "nifffxxxxxxxxxx"; char const LiquidTypefmt[] = "nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; char const LockEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; -char const MailTemplateEntryfmt[] = "nxxxxxxxxxxxxxxxxxssssssssssssssssx"; -char const MapEntryfmt[] = "nxiixssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxiii"; -char const MapDifficultyEntryfmt[] = "diisxxxxxxxxxxxxxxxxiix"; -char const MovieEntryfmt[] = "nxx"; -char const OverrideSpellDatafmt[] = "niiiiiiiiiix"; +char const PhaseEntryfmt[] = "nsi"; +char const PhaseGroupfmt[] = "nii"; +char const MailTemplateEntryfmt[] = "nxs"; +char const MapEntryfmt[] = "nxiixxsixxixiffxiiii"; +char const MapDifficultyEntryfmt[] = "diisiix"; +char const MovieEntryfmt[] = "nxxx"; +char const MountCapabilityfmt[] = "niiiiiii"; +char const MountTypefmt[] = "niiiiiiiiiiiiiiiiiiiiiiii"; +char const NameGenfmt[] = "dsii"; +char const NumTalentsAtLevelfmt[] = "df"; +char const OverrideSpellDatafmt[] = "niiiiiiiiiixx"; char const QuestFactionRewardfmt[] = "niiiiiiiiii"; -char const QuestSortEntryfmt[] = "nxxxxxxxxxxxxxxxxx"; +char const QuestSortEntryfmt[] = "nx"; char const QuestXPfmt[] = "niiiiiiiiii"; char const PowerDisplayfmt[] = "nixxxx"; char const PvPDifficultyfmt[] = "diiiii"; char const RandomPropertiesPointsfmt[] = "niiiiiiiiiiiiiii"; -char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiii"; -char const ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiii"; -char const SkillLinefmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi"; -char const SkillLineAbilityfmt[] = "niiiixxiiiiixx"; -char const SkillRaceClassInfofmt[] = "diiiixix"; +char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiixi"; +char const ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"; +char const SkillLinefmt[] = "nisxixi"; +char const SkillLineAbilityfmt[] = "niiiixxiiiiiii"; +char const SkillRaceClassInfofmt[] = "diiiixxix"; char const SkillTiersfmt[] = "nxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiii"; -char const SoundEntriesfmt[] = "nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const SoundEntriesfmt[] = "nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; char const SpellCastTimefmt[] = "nixx"; -char const SpellCategoryfmt[] = "ni"; +char const SpellCategoriesEntryfmt[] = "diiiiii"; +char const SpellCategoryfmt[] = "nixx"; char const SpellDifficultyfmt[] = "niiii"; const std::string CustomSpellDifficultyfmt = "ppppp"; const std::string CustomSpellDifficultyIndex = "id"; char const SpellDurationfmt[] = "niii"; -char const SpellEntryfmt[] = "niiiiiiiiiiiixixiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiixfffxxxiiiiixxfffxx"; -const std::string CustomSpellEntryfmt = "papppppppppppapapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaaaaaa"; +// 0 10 20 26 +char const SpellEffectEntryfmt[] = "nifiiiffiiiiiifiifiiiiiiiix"; +const std::string CustomSpellEffectEntryfmt = "ppppppppppapppappppppppppp"; +const std::string CustomSpellEffectEntryIndex = "Id"; +// 0 10 20 30 40 47 +char const SpellEntryfmt[] = "niiiiiiiiiiiiiiifiiiissxxiixxifiiiiiiixiiiiiiiix"; +const std::string CustomSpellEntryfmt = "ppppppppppppppapaaaaaaaaapaaaaaapapppaapppaaapa"; const std::string CustomSpellEntryIndex = "Id"; -char const SpellFocusObjectfmt[] = "nxxxxxxxxxxxxxxxxx"; -char const SpellItemEnchantmentfmt[] = "nxiiiiiixxxiiissssssssssssssssxiiiiiii"; +char const SpellFocusObjectfmt[] = "nx"; +char const SpellItemEnchantmentfmt[] = "nxiiiiiixxxiiisiiiiiiix"; char const SpellItemEnchantmentConditionfmt[] = "nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX"; char const SpellRadiusfmt[] = "nfff"; -char const SpellRangefmt[] = "nffffixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const SpellRangefmt[] = "nffffixx"; +char const SpellReagentsEntryfmt[] = "diiiiiiiiiiiiiiii"; +char const SpellScalingEntryfmt[] = "diiiiffffffffffi"; +char const SpellTotemsEntryfmt[] = "niiii"; +char const SpellTargetRestrictionsEntryfmt[] = "nxiiii"; +char const SpellPowerEntryfmt[] = "diiiiixf"; +char const SpellInterruptsEntryfmt[] = "dixixi"; +char const SpellEquippedItemsEntryfmt[] = "diii"; +char const SpellAuraOptionsEntryfmt[] = "niiii"; +char const SpellAuraRestrictionsEntryfmt[] = "diiiiiiii"; +char const SpellCastingRequirementsEntryfmt[] = "dixxixi"; +char const SpellClassOptionsEntryfmt[] = "dxiiiix"; +char const SpellCooldownsEntryfmt[] = "diii"; +char const SpellLevelsEntryfmt[] = "diii"; char const SpellRuneCostfmt[] = "niiii"; -char const SpellShapeshiftfmt[] = "nxxxxxxxxxxxxxxxxxxiixiiixxiiiiiiii"; +char const SpellShapeshiftEntryfmt[] = "nixixx"; +char const SpellShapeshiftFormfmt[] = "nxxiixiiixxiiiiiiiixx"; char const StableSlotPricesfmt[] = "ni"; char const SummonPropertiesfmt[] = "niiiii"; -char const TalentEntryfmt[] = "niiiiiiiixxxxixxixxxxxx"; -char const TalentTabEntryfmt[] = "nxxxxxxxxxxxxxxxxxxxiiix"; -char const TaxiNodesEntryfmt[] = "nifffssssssssssssssssxii"; +char const TalentEntryfmt[] = "niiiiiiiiixxixxxxxx"; +char const TalentTabEntryfmt[] = "nxxiiixxxii"; +char const TalentTreePrimarySpellsfmt[] = "diix"; +char const TaxiNodesEntryfmt[] = "nifffsiiixx"; char const TaxiPathEntryfmt[] = "niii"; char const TaxiPathNodeEntryfmt[] = "diiifffiiii"; -char const TeamContributionPointsfmt[] = "df"; -char const TotemCategoryEntryfmt[] = "nxxxxxxxxxxxxxxxxxii"; +char const TotemCategoryEntryfmt[] = "nxii"; +char const UnitPowerBarfmt[] = "niixxxxxxxxxxxxxxxxxxxxxxxx"; char const TransportAnimationfmt[] = "diifffx"; char const TransportRotationfmt[] = "diiffff"; char const VehicleEntryfmt[] = "niffffiiiiiiiifffffffffffffffssssfifiixx"; -char const VehicleSeatEntryfmt[] = "niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx"; -char const WMOAreaTableEntryfmt[] = "niiixxxxxiixxxxxxxxxxxxxxxxx"; -char const WorldMapAreaEntryfmt[] = "xinxffffixx"; -char const WorldMapOverlayEntryfmt[] = "nxiiiixxxxxxxxxxx"; -char const WorldSafeLocsEntryfmt[] = "nifffxxxxxxxxxxxxxxxxx"; +char const VehicleSeatEntryfmt[] = "niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxxxxxxxxxx"; +char const WMOAreaTableEntryfmt[] = "niiixxxxxiixxxx"; +char const WorldMapAreaEntryfmt[] = "xinxffffixxxxx"; +char const WorldMapOverlayEntryfmt[] = "nxiiiixxxxxxxxx"; +char const WorldSafeLocsEntryfmt[] = "nifffx"; #endif diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h index 0030dfa6c4b..efafd5d3afd 100644 --- a/src/server/game/DungeonFinding/LFG.h +++ b/src/server/game/DungeonFinding/LFG.h @@ -44,17 +44,21 @@ enum LfgUpdateType LFG_UPDATETYPE_DEFAULT = 0, // Internal Use LFG_UPDATETYPE_LEADER_UNK1 = 1, // FIXME: At group leave LFG_UPDATETYPE_ROLECHECK_ABORTED = 4, - LFG_UPDATETYPE_JOIN_QUEUE = 5, - LFG_UPDATETYPE_ROLECHECK_FAILED = 6, - LFG_UPDATETYPE_REMOVED_FROM_QUEUE = 7, - LFG_UPDATETYPE_PROPOSAL_FAILED = 8, - LFG_UPDATETYPE_PROPOSAL_DECLINED = 9, - LFG_UPDATETYPE_GROUP_FOUND = 10, - LFG_UPDATETYPE_ADDED_TO_QUEUE = 12, - LFG_UPDATETYPE_PROPOSAL_BEGIN = 13, - LFG_UPDATETYPE_UPDATE_STATUS = 14, - LFG_UPDATETYPE_GROUP_MEMBER_OFFLINE = 15, - LFG_UPDATETYPE_GROUP_DISBAND_UNK16 = 16, // FIXME: Sometimes at group disband + LFG_UPDATETYPE_JOIN_QUEUE = 6, + LFG_UPDATETYPE_ROLECHECK_FAILED = 7, + LFG_UPDATETYPE_REMOVED_FROM_QUEUE = 8, + LFG_UPDATETYPE_PROPOSAL_FAILED = 9, + LFG_UPDATETYPE_PROPOSAL_DECLINED = 10, + LFG_UPDATETYPE_GROUP_FOUND = 11, + LFG_UPDATETYPE_ADDED_TO_QUEUE = 13, + LFG_UPDATETYPE_PROPOSAL_BEGIN = 14, + LFG_UPDATETYPE_UPDATE_STATUS = 15, + LFG_UPDATETYPE_GROUP_MEMBER_OFFLINE = 16, + LFG_UPDATETYPE_GROUP_DISBAND_UNK16 = 17, // FIXME: Sometimes at group disband + LFG_UPDATETYPE_JOIN_QUEUE_INITIAL = 24, + LFG_UPDATETYPE_DUNGEON_FINISHED = 25, + LFG_UPDATETYPE_PARTY_ROLE_NOT_AVAILABLE = 43, + LFG_UPDATETYPE_JOIN_LFG_OBJECT_FAILED = 45, }; enum LfgState @@ -94,8 +98,18 @@ enum LfgAnswer LFG_ANSWER_AGREE = 1 }; +struct LfgLockInfoData +{ + LfgLockInfoData(uint32 _lockStatus = 0, uint16 _requiredItemLevel = 0, float _currentItemLevel = 0) : + lockStatus(_lockStatus), requiredItemLevel(_requiredItemLevel), currentItemLevel(_currentItemLevel) { } + + uint32 lockStatus; + uint16 requiredItemLevel; + float currentItemLevel; +}; + typedef std::set<uint32> LfgDungeonSet; -typedef std::map<uint32, uint32> LfgLockMap; +typedef std::map<uint32, LfgLockInfoData> LfgLockMap; typedef std::map<uint64, LfgLockMap> LfgLockPartyMap; typedef std::set<uint64> LfgGuidSet; typedef std::list<uint64> LfgGuidList; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 076ac7982ec..0efc7fd6230 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -194,11 +194,10 @@ void LFGMgr::LoadLFGDungeons(bool reload /* = false */) } // Fill teleport locations from DB - QueryResult result = WorldDatabase.Query("SELECT dungeonId, position_x, position_y, position_z, orientation FROM lfg_entrances"); - + QueryResult result = WorldDatabase.Query("SELECT dungeonId, position_x, position_y, position_z, orientation, requiredItemLevel FROM lfg_dungeon_template"); if (!result) { - TC_LOG_ERROR("server.loading", ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!"); + TC_LOG_ERROR("server.loading", ">> Loaded 0 lfg dungeon templates. DB table `lfg_dungeon_template` is empty!"); return; } @@ -215,17 +214,18 @@ void LFGMgr::LoadLFGDungeons(bool reload /* = false */) continue; } - LFGDungeonData& data = dungeonItr->second; - data.x = fields[1].GetFloat(); - data.y = fields[2].GetFloat(); - data.z = fields[3].GetFloat(); - data.o = fields[4].GetFloat(); + LFGDungeonData& data = dungeonItr->second; + data.x = fields[1].GetFloat(); + data.y = fields[2].GetFloat(); + data.z = fields[3].GetFloat(); + data.o = fields[4].GetFloat(); + data.requiredItemLevel = fields[5].GetUInt16(); ++count; } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u lfg entrance positions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u lfg dungeon templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); // Fill all other teleport coords from areatriggers for (LFGDungeonContainer::iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr) @@ -235,10 +235,10 @@ void LFGMgr::LoadLFGDungeons(bool reload /* = false */) // No teleport coords in database, load from areatriggers if (dungeon.type != LFG_TYPE_RANDOM && dungeon.x == 0.0f && dungeon.y == 0.0f && dungeon.z == 0.0f) { - AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon.map); + AreaTriggerStruct const* at = sObjectMgr->GetMapEntranceTrigger(dungeon.map); if (!at) { - TC_LOG_ERROR("sql.sql", "Failed to load dungeon %s, cant find areatrigger for map %u", dungeon.name.c_str(), dungeon.map); + TC_LOG_ERROR("sql.sql", "Failed to load dungeon %s (Id: %u), cant find areatrigger for map %u", dungeon.name.c_str(), dungeon.id, dungeon.map); continue; } @@ -255,9 +255,7 @@ void LFGMgr::LoadLFGDungeons(bool reload /* = false */) } if (reload) - { CachedDungeonMapStore.clear(); - } } void LFGMgr::Update(uint32 diff) @@ -282,7 +280,7 @@ void LFGMgr::Update(uint32 diff) RestoreState(guid, "Remove Obsolete RoleCheck"); SendLfgRoleCheckUpdate(guid, roleCheck); if (guid == roleCheck.leader) - SendLfgJoinResult(guid, LfgJoinResultData(LFG_JOIN_FAILED, LFG_ROLECHECK_MISSING_ROLE)); + SendLfgJoinResult(guid, LfgJoinResultData(LFG_JOIN_ROLE_CHECK_FAILED, LFG_ROLECHECK_MISSING_ROLE)); } RestoreState(itRoleCheck->first, "Remove Obsolete RoleCheck"); @@ -339,10 +337,10 @@ void LFGMgr::Update(uint32 diff) if (uint64 gguid = GetGroup(guid)) { SetState(gguid, LFG_STATE_PROPOSAL); - SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid))); + SendLfgUpdateStatus(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)), true); } else - SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid))); + SendLfgUpdateStatus(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)), false); SendLfgUpdateProposal(guid, proposal); } @@ -356,7 +354,7 @@ void LFGMgr::Update(uint32 diff) { m_QueueTimer = 0; for (LfgQueueContainer::iterator it = QueuesStore.begin(); it != QueuesStore.end(); ++it) - it->second.UpdateQueueTimers(currTime); + it->second.UpdateQueueTimers(it->first, currTime); } else m_QueueTimer += diff; @@ -423,7 +421,7 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const if (Player* plrg = itr->GetSource()) { if (!plrg->GetSession()->HasPermission(rbac::RBAC_PERM_JOIN_DUNGEON_FINDER)) - joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS; + joinData.result = LFG_JOIN_INTERNAL_ERROR; if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER)) joinData.result = LFG_JOIN_PARTY_DESERTER; else if (plrg->HasAura(LFG_SPELL_DUNGEON_COOLDOWN)) @@ -485,7 +483,7 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const // if we have lockmap then there are no compatible dungeons GetCompatibleDungeons(dungeons, players, joinData.lockmap); if (dungeons.empty()) - joinData.result = grp ? LFG_JOIN_PARTY_NOT_MEET_REQS : LFG_JOIN_NOT_MEET_REQS; + joinData.result = grp ? LFG_JOIN_INTERNAL_ERROR : LFG_JOIN_NOT_MEET_REQS; } } @@ -534,7 +532,7 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const if (Player* plrg = itr->GetSource()) { uint64 pguid = plrg->GetGUID(); - plrg->GetSession()->SendLfgUpdateParty(updateData); + plrg->GetSession()->SendLfgUpdateStatus(updateData, true); SetState(pguid, LFG_STATE_ROLECHECK); if (!isContinue) SetSelectedDungeons(pguid, dungeons); @@ -565,7 +563,7 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const } // Send update to player player->GetSession()->SendLfgJoinResult(joinData); - player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE, dungeons, comment)); + player->GetSession()->SendLfgUpdateStatus(LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE, dungeons, comment), false); SetState(gguid, LFG_STATE_QUEUED); SetRoles(guid, roles); debugNames.append(player->GetName()); @@ -600,14 +598,14 @@ void LFGMgr::LeaveLfg(uint64 guid) for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it) { SetState(*it, LFG_STATE_NONE); - SendLfgUpdateParty(*it, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE)); + SendLfgUpdateStatus(*it, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE), true); } } else { LFGQueue& queue = GetQueue(guid); queue.RemoveFromQueue(guid); - SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE)); + SendLfgUpdateStatus(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE), false); SetState(guid, LFG_STATE_NONE); } break; @@ -696,7 +694,11 @@ void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* else dungeons = roleCheck.dungeons; - LfgJoinResultData joinData = LfgJoinResultData(LFG_JOIN_FAILED, roleCheck.state); + LfgJoinResult joinResult = LFG_JOIN_FAILED; + if (roleCheck.state == LFG_ROLECHECK_MISSING_ROLE || roleCheck.state == LFG_ROLECHECK_WRONG_ROLES) + joinResult = LFG_JOIN_ROLE_CHECK_FAILED; + + LfgJoinResultData joinData = LfgJoinResultData(joinResult, roleCheck.state); for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) { uint64 pguid = it->first; @@ -712,12 +714,12 @@ void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* case LFG_ROLECHECK_FINISHED: SetState(pguid, LFG_STATE_QUEUED); SetRoles(pguid, it->second); - SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, GetComment(pguid))); + SendLfgUpdateStatus(pguid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, GetComment(pguid)), true); break; default: if (roleCheck.leader == pguid) SendLfgJoinResult(pguid, joinData); - SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ROLECHECK_FAILED)); + SendLfgUpdateStatus(pguid, LfgUpdateData(LFG_UPDATETYPE_ROLECHECK_FAILED), true); RestoreState(pguid, "Rolecheck Failed"); break; } @@ -982,16 +984,16 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) if (gguid) { waitTime = int32((joinTime - queue.GetJoinTime(gguid)) / IN_MILLISECONDS); - SendLfgUpdateParty(pguid, updateData); + SendLfgUpdateStatus(pguid, updateData, false); } else { waitTime = int32((joinTime - queue.GetJoinTime(pguid)) / IN_MILLISECONDS); - SendLfgUpdatePlayer(pguid, updateData); + SendLfgUpdateStatus(pguid, updateData, false); } updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE; - SendLfgUpdatePlayer(pguid, updateData); - SendLfgUpdateParty(pguid, updateData); + SendLfgUpdateStatus(pguid, updateData, true); + SendLfgUpdateStatus(pguid, updateData, false); // Update timers uint8 role = GetRoles(pguid); @@ -1083,10 +1085,10 @@ void LFGMgr::RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdate if (gguid != guid) { RestoreState(it->second.group, "Proposal Fail (someone in group didn't accepted)"); - SendLfgUpdateParty(guid, updateData); + SendLfgUpdateStatus(guid, updateData, true); } else - SendLfgUpdatePlayer(guid, updateData); + SendLfgUpdateStatus(guid, updateData, false); } else { @@ -1095,10 +1097,10 @@ void LFGMgr::RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdate if (gguid != guid) { SetState(gguid, LFG_STATE_QUEUED); - SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid))); + SendLfgUpdateStatus(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)), true); } else - SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid))); + SendLfgUpdateStatus(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)), false); } } @@ -1559,39 +1561,39 @@ LfgLockMap const LFGMgr::GetLockedDungeons(uint64 guid) if (!dungeon) // should never happen - We provide a list from sLFGDungeonStore continue; - uint32 lockData = 0; + uint32 lockStatus = 0; if (denyJoin) - lockData = LFG_LOCKSTATUS_RAID_LOCKED; + lockStatus = LFG_LOCKSTATUS_RAID_LOCKED; else if (dungeon->expansion > expansion) - lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; + lockStatus = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player)) - lockData = LFG_LOCKSTATUS_RAID_LOCKED; + lockStatus = LFG_LOCKSTATUS_RAID_LOCKED; else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty))) - lockData = LFG_LOCKSTATUS_RAID_LOCKED; + lockStatus = LFG_LOCKSTATUS_RAID_LOCKED; else if (dungeon->minlevel > level) - lockData = LFG_LOCKSTATUS_TOO_LOW_LEVEL; + lockStatus = LFG_LOCKSTATUS_TOO_LOW_LEVEL; else if (dungeon->maxlevel < level) - lockData = LFG_LOCKSTATUS_TOO_HIGH_LEVEL; + lockStatus = LFG_LOCKSTATUS_TOO_HIGH_LEVEL; else if (dungeon->seasonal && !IsSeasonActive(dungeon->id)) - lockData = LFG_LOCKSTATUS_NOT_IN_SEASON; + lockStatus = LFG_LOCKSTATUS_NOT_IN_SEASON; + else if (dungeon->requiredItemLevel > player->GetAverageItemLevel()) + lockStatus = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; else if (AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty))) { - if (ar->item_level && player->GetAverageItemLevel() < ar->item_level) - lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; - else if (ar->achievement && !player->HasAchieved(ar->achievement)) - lockData = LFG_LOCKSTATUS_MISSING_ACHIEVEMENT; + if (ar->achievement && !player->HasAchieved(ar->achievement)) + lockStatus = LFG_LOCKSTATUS_MISSING_ACHIEVEMENT; else if (player->GetTeam() == ALLIANCE && ar->quest_A && !player->GetQuestRewardStatus(ar->quest_A)) - lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; + lockStatus = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; else if (player->GetTeam() == HORDE && ar->quest_H && !player->GetQuestRewardStatus(ar->quest_H)) - lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; + lockStatus = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; else if (ar->item) { if (!player->HasItemCount(ar->item) && (!ar->item2 || !player->HasItemCount(ar->item2))) - lockData = LFG_LOCKSTATUS_MISSING_ITEM; + lockStatus = LFG_LOCKSTATUS_MISSING_ITEM; } else if (ar->item2 && !player->HasItemCount(ar->item2)) - lockData = LFG_LOCKSTATUS_MISSING_ITEM; + lockStatus = LFG_LOCKSTATUS_MISSING_ITEM; } /* @todo VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED) @@ -1600,8 +1602,8 @@ LfgLockMap const LFGMgr::GetLockedDungeons(uint64 guid) lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL; */ - if (lockData) - lock[dungeon->Entry()] = lockData; + if (lockStatus) + lock[dungeon->Entry()] = LfgLockInfoData(lockStatus, dungeon->requiredItemLevel, player->GetAverageItemLevel()); } return lock; @@ -1712,7 +1714,7 @@ void LFGMgr::RemoveGroupData(uint64 guid) if (state != LFG_STATE_PROPOSAL) { SetState(playerGUID, LFG_STATE_NONE); - SendLfgUpdateParty(playerGUID, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE)); + SendLfgUpdateStatus(playerGUID, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE), true); } } GroupsStore.erase(it); @@ -1794,16 +1796,10 @@ void LFGMgr::SendLfgRoleCheckUpdate(uint64 guid, LfgRoleCheck const& roleCheck) player->GetSession()->SendLfgRoleCheckUpdate(roleCheck); } -void LFGMgr::SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data) -{ - if (Player* player = ObjectAccessor::FindPlayer(guid)) - player->GetSession()->SendLfgUpdatePlayer(data); -} - -void LFGMgr::SendLfgUpdateParty(uint64 guid, LfgUpdateData const& data) +void LFGMgr::SendLfgUpdateStatus(uint64 guid, LfgUpdateData const& data, bool party) { if (Player* player = ObjectAccessor::FindPlayer(guid)) - player->GetSession()->SendLfgUpdateParty(data); + player->GetSession()->SendLfgUpdateStatus(data, party); } void LFGMgr::SendLfgJoinResult(uint64 guid, LfgJoinResultData const& data) @@ -1835,18 +1831,22 @@ bool LFGMgr::IsLfgGroup(uint64 guid) return guid && IS_GROUP_GUID(guid) && GroupsStore[guid].IsLfgGroup(); } -LFGQueue& LFGMgr::GetQueue(uint64 guid) +uint8 LFGMgr::GetQueueId(uint64 guid) { - uint8 queueId = 0; if (IS_GROUP_GUID(guid)) { LfgGuidSet const& players = GetPlayers(guid); uint64 pguid = players.empty() ? 0 : (*players.begin()); if (pguid) - queueId = GetTeam(pguid); + return GetTeam(pguid); } - else - queueId = GetTeam(guid); + + return GetTeam(guid); +} + +LFGQueue& LFGMgr::GetQueue(uint64 guid) +{ + uint8 queueId = GetQueueId(guid); return QueuesStore[queueId]; } @@ -1861,6 +1861,16 @@ bool LFGMgr::AllQueued(LfgGuidList const& check) return true; } +time_t LFGMgr::GetQueueJoinTime(uint64 guid) +{ + uint8 queueId = GetQueueId(guid); + LfgQueueContainer::const_iterator itr = QueuesStore.find(queueId); + if (itr != QueuesStore.end()) + return itr->second.GetJoinTime(guid); + + return 0; +} + // Only for debugging purposes void LFGMgr::Clean() { diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 547d026dee0..b04b4f1a7ab 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -93,23 +93,24 @@ enum LfgTeleportError enum LfgJoinResult { // 3 = No client reaction | 18 = "Rolecheck failed" - LFG_JOIN_OK = 0, // Joined (no client msg) - LFG_JOIN_FAILED = 1, // RoleCheck Failed - LFG_JOIN_GROUPFULL = 2, // Your group is full - LFG_JOIN_INTERNAL_ERROR = 4, // Internal LFG Error - LFG_JOIN_NOT_MEET_REQS = 5, // You do not meet the requirements for the chosen dungeons - LFG_JOIN_PARTY_NOT_MEET_REQS = 6, // One or more party members do not meet the requirements for the chosen dungeons - LFG_JOIN_MIXED_RAID_DUNGEON = 7, // You cannot mix dungeons, raids, and random when picking dungeons - LFG_JOIN_MULTI_REALM = 8, // The dungeon you chose does not support players from multiple realms - LFG_JOIN_DISCONNECTED = 9, // One or more party members are pending invites or disconnected - LFG_JOIN_PARTY_INFO_FAILED = 10, // Could not retrieve information about some party members - LFG_JOIN_DUNGEON_INVALID = 11, // One or more dungeons was not valid - LFG_JOIN_DESERTER = 12, // You can not queue for dungeons until your deserter debuff wears off - LFG_JOIN_PARTY_DESERTER = 13, // One or more party members has a deserter debuff - LFG_JOIN_RANDOM_COOLDOWN = 14, // You can not queue for random dungeons while on random dungeon cooldown - LFG_JOIN_PARTY_RANDOM_COOLDOWN = 15, // One or more party members are on random dungeon cooldown - LFG_JOIN_TOO_MUCH_MEMBERS = 16, // You can not enter dungeons with more that 5 party members - LFG_JOIN_USING_BG_SYSTEM = 17 // You can not use the dungeon system while in BG or arenas + LFG_JOIN_OK = 0x00, // Joined (no client msg) + LFG_JOIN_FAILED = 0x1B, // RoleCheck Failed + LFG_JOIN_GROUPFULL = 0x1C, // Your group is full + LFG_JOIN_INTERNAL_ERROR = 0x1E, // Internal LFG Error + LFG_JOIN_NOT_MEET_REQS = 0x1F, // You do not meet the requirements for the chosen dungeons + //LFG_JOIN_PARTY_NOT_MEET_REQS = 6, // One or more party members do not meet the requirements for the chosen dungeons + LFG_JOIN_MIXED_RAID_DUNGEON = 0x20, // You cannot mix dungeons, raids, and random when picking dungeons + LFG_JOIN_MULTI_REALM = 0x21, // The dungeon you chose does not support players from multiple realms + LFG_JOIN_DISCONNECTED = 0x22, // One or more party members are pending invites or disconnected + LFG_JOIN_PARTY_INFO_FAILED = 0x23, // Could not retrieve information about some party members + LFG_JOIN_DUNGEON_INVALID = 0x24, // One or more dungeons was not valid + LFG_JOIN_DESERTER = 0x25, // You can not queue for dungeons until your deserter debuff wears off + LFG_JOIN_PARTY_DESERTER = 0x26, // One or more party members has a deserter debuff + LFG_JOIN_RANDOM_COOLDOWN = 0x27, // You can not queue for random dungeons while on random dungeon cooldown + LFG_JOIN_PARTY_RANDOM_COOLDOWN = 0x28, // One or more party members are on random dungeon cooldown + LFG_JOIN_TOO_MUCH_MEMBERS = 0x29, // You can not enter dungeons with more that 5 party members + LFG_JOIN_USING_BG_SYSTEM = 0x2A, // You can not use the dungeon system while in BG or arenas + LFG_JOIN_ROLE_CHECK_FAILED = 0x2B // Role check failed, client shows special error }; /// Role check states @@ -156,7 +157,7 @@ struct LfgJoinResultData LfgLockPartyMap lockmap; }; -// Data needed by SMSG_LFG_UPDATE_PARTY and SMSG_LFG_UPDATE_PLAYER +// Data needed by SMSG_LFG_UPDATE_STATUS struct LfgUpdateData { LfgUpdateData(LfgUpdateType _type = LFG_UPDATETYPE_DEFAULT): updateType(_type), state(LFG_STATE_NONE), comment("") { } @@ -174,12 +175,14 @@ struct LfgUpdateData // Data needed by SMSG_LFG_QUEUE_STATUS struct LfgQueueStatusData { - LfgQueueStatusData(uint32 _dungeonId = 0, int32 _waitTime = -1, int32 _waitTimeAvg = -1, int32 _waitTimeTank = -1, int32 _waitTimeHealer = -1, + LfgQueueStatusData(uint8 _queueId = 0, uint32 _dungeonId = 0, time_t _joinTime = 0, int32 _waitTime = -1, int32 _waitTimeAvg = -1, int32 _waitTimeTank = -1, int32 _waitTimeHealer = -1, int32 _waitTimeDps = -1, uint32 _queuedTime = 0, uint8 _tanks = 0, uint8 _healers = 0, uint8 _dps = 0) : - dungeonId(_dungeonId), waitTime(_waitTime), waitTimeAvg(_waitTimeAvg), waitTimeTank(_waitTimeTank), waitTimeHealer(_waitTimeHealer), - waitTimeDps(_waitTimeDps), queuedTime(_queuedTime), tanks(_tanks), healers(_healers), dps(_dps) { } + queueId(_queueId), dungeonId(_dungeonId), joinTime(_joinTime), waitTime(_waitTime), waitTimeAvg(_waitTimeAvg), waitTimeTank(_waitTimeTank), + waitTimeHealer(_waitTimeHealer), waitTimeDps(_waitTimeDps), queuedTime(_queuedTime), tanks(_tanks), healers(_healers), dps(_dps) { } + uint8 queueId; uint32 dungeonId; + time_t joinTime; int32 waitTime; int32 waitTimeAvg; int32 waitTimeTank; @@ -265,12 +268,14 @@ struct LfgPlayerBoot struct LFGDungeonData { LFGDungeonData(): id(0), name(""), map(0), type(0), expansion(0), group(0), minlevel(0), - maxlevel(0), difficulty(REGULAR_DIFFICULTY), seasonal(false), x(0.0f), y(0.0f), z(0.0f), o(0.0f) + maxlevel(0), difficulty(REGULAR_DIFFICULTY), seasonal(false), x(0.0f), y(0.0f), z(0.0f), o(0.0f), + requiredItemLevel(0) { } - LFGDungeonData(LFGDungeonEntry const* dbc): id(dbc->ID), name(dbc->name[0]), map(dbc->map), + LFGDungeonData(LFGDungeonEntry const* dbc): id(dbc->ID), name(dbc->name), map(dbc->map), type(dbc->type), expansion(dbc->expansion), group(dbc->grouptype), minlevel(dbc->minlevel), maxlevel(dbc->maxlevel), difficulty(Difficulty(dbc->difficulty)), - seasonal((dbc->flags & LFG_FLAG_SEASONAL) != 0), x(0.0f), y(0.0f), z(0.0f), o(0.0f) + seasonal((dbc->flags & LFG_FLAG_SEASONAL) != 0), x(0.0f), y(0.0f), z(0.0f), o(0.0f), + requiredItemLevel(0) { } uint32 id; @@ -284,6 +289,7 @@ struct LFGDungeonData Difficulty difficulty; bool seasonal; float x, y, z, o; + uint16 requiredItemLevel; // Helpers uint32 Entry() const { return id + (type << 24); } @@ -408,8 +414,12 @@ class LFGMgr uint8 GetPlayerCount(uint64 guid); /// Add a new Proposal uint32 AddProposal(LfgProposal& proposal); + /// Returns queue id + uint8 GetQueueId(uint64 guid); /// Checks if all players are queued bool AllQueued(LfgGuidList const& check); + /// Gets queue join time + time_t GetQueueJoinTime(uint64 guid); /// Checks if given roles match, modifies given roles map with new roles static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); /// Checks if given players are ignoring each other @@ -435,7 +445,8 @@ class LFGMgr void MakeNewGroup(LfgProposal const& proposal); // Generic - LFGQueue &GetQueue(uint64 guid); + LFGQueue& GetQueue(uint64 guid); + LfgDungeonSet const& GetDungeonsByRandom(uint32 randomdungeon); LfgType GetDungeonType(uint32 dungeon); @@ -443,8 +454,7 @@ class LFGMgr void SendLfgJoinResult(uint64 guid, LfgJoinResultData const& data); void SendLfgRoleChosen(uint64 guid, uint64 pguid, uint8 roles); void SendLfgRoleCheckUpdate(uint64 guid, LfgRoleCheck const& roleCheck); - void SendLfgUpdateParty(uint64 guid, LfgUpdateData const& data); - void SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data); + void SendLfgUpdateStatus(uint64 guid, LfgUpdateData const& data, bool party); void SendLfgUpdateProposal(uint64 guid, LfgProposal const& proposal); LfgGuidSet const& GetPlayers(uint64 guid); diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index 67a9f0afc69..a44c7780c6b 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -537,7 +537,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check) return LFG_COMPATIBLES_MATCH; } -void LFGQueue::UpdateQueueTimers(time_t currTime) +void LFGQueue::UpdateQueueTimers(uint8 queueId, time_t currTime) { TC_LOG_TRACE("lfg.queue.timers.update", "Updating queue timers..."); for (LfgQueueDataContainer::iterator itQueue = QueueDataStore.begin(); itQueue != QueueDataStore.end(); ++itQueue) @@ -578,7 +578,7 @@ void LFGQueue::UpdateQueueTimers(time_t currTime) if (queueinfo.bestCompatible.empty()) FindBestCompatibleInQueue(itQueue); - LfgQueueStatusData queueData(dungeonId, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, queueinfo.tanks, queueinfo.healers, queueinfo.dps); + LfgQueueStatusData queueData(queueId, dungeonId, queueinfo.joinTime, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, queueinfo.tanks, queueinfo.healers, queueinfo.dps); for (LfgRolesMap::const_iterator itPlayer = queueinfo.roles.begin(); itPlayer != queueinfo.roles.end(); ++itPlayer) { uint64 pguid = itPlayer->first; @@ -587,9 +587,13 @@ void LFGQueue::UpdateQueueTimers(time_t currTime) } } -time_t LFGQueue::GetJoinTime(uint64 guid) +time_t LFGQueue::GetJoinTime(uint64 guid) const { - return QueueDataStore[guid].joinTime; + LfgQueueDataContainer::const_iterator itr = QueueDataStore.find(guid); + if (itr != QueueDataStore.end()) + return itr->second.joinTime; + + return 0; } std::string LFGQueue::DumpQueueInfo() const diff --git a/src/server/game/DungeonFinding/LFGQueue.h b/src/server/game/DungeonFinding/LFGQueue.h index b66121802c6..0312c926991 100644 --- a/src/server/game/DungeonFinding/LFGQueue.h +++ b/src/server/game/DungeonFinding/LFGQueue.h @@ -100,8 +100,8 @@ class LFGQueue void UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId); // Update Queue timers - void UpdateQueueTimers(time_t currTime); - time_t GetJoinTime(uint64 guid); + void UpdateQueueTimers(uint8 queueId, time_t currTime); + time_t GetJoinTime(uint64 guid) const; // Find new group uint8 FindGroups(); diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp index 181e04e04fc..6a38afb398d 100644 --- a/src/server/game/DungeonFinding/LFGScripts.cpp +++ b/src/server/game/DungeonFinding/LFGScripts.cpp @@ -177,7 +177,7 @@ void LFGGroupScript::OnRemoveMember(Group* group, uint64 guid, RemoveMethod meth //else if (state == LFG_STATE_BOOT) // Update internal kick cooldown of kicked - player->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_LEADER_UNK1)); + player->GetSession()->SendLfgUpdateStatus(LfgUpdateData(LFG_UPDATETYPE_LEADER_UNK1), true); if (isLFG && player->GetMap()->IsDungeon()) // Teleport player out the dungeon sLFGMgr->TeleportPlayer(player, true); } diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp new file mode 100644 index 00000000000..599f486b949 --- /dev/null +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ObjectAccessor.h" +#include "Unit.h" +#include "SpellInfo.h" +#include "Log.h" +#include "AreaTrigger.h" + +AreaTrigger::AreaTrigger() : WorldObject(false), _duration(0) +{ + m_objectType |= TYPEMASK_AREATRIGGER; + m_objectTypeId = TYPEID_AREATRIGGER; + + m_updateFlag = UPDATEFLAG_STATIONARY_POSITION; + + m_valuesCount = AREATRIGGER_END; +} + +AreaTrigger::~AreaTrigger() +{ +} + +void AreaTrigger::AddToWorld() +{ + ///- Register the AreaTrigger for guid lookup and for caster + if (!IsInWorld()) + { + sObjectAccessor->AddObject(this); + WorldObject::AddToWorld(); + } +} + +void AreaTrigger::RemoveFromWorld() +{ + ///- Remove the AreaTrigger from the accessor and from all lists of objects in world + if (IsInWorld()) + { + WorldObject::RemoveFromWorld(); + sObjectAccessor->RemoveObject(this); + } +} + +bool AreaTrigger::CreateAreaTrigger(uint32 guidlow, uint32 triggerEntry, Unit* caster, SpellInfo const* spell, Position const& pos) +{ + SetMap(caster->GetMap()); + Relocate(pos); + if (!IsPositionValid()) + { + TC_LOG_ERROR("misc", "AreaTrigger (spell %u) not created. Invalid coordinates (X: %f Y: %f)", spell->Id, GetPositionX(), GetPositionY()); + return false; + } + + WorldObject::_Create(guidlow, HIGHGUID_AREATRIGGER, caster->GetPhaseMask()); + + SetEntry(triggerEntry); + SetDuration(spell->GetDuration()); + SetObjectScale(1); + + SetUInt32Value(AREATRIGGER_SPELLID, spell->Id); + SetUInt32Value(AREATRIGGER_SPELLVISUALID, spell->SpellVisual[0]); + SetUInt32Value(AREATRIGGER_DURATION, spell->GetDuration()); + SetFloatValue(AREATRIGGER_FINAL_POS + 0, pos.GetPositionX()); + SetFloatValue(AREATRIGGER_FINAL_POS + 1, pos.GetPositionY()); + SetFloatValue(AREATRIGGER_FINAL_POS + 2, pos.GetPositionZ()); + + for (auto phase : caster->GetPhases()) + SetInPhase(phase, false, true); + + if (!GetMap()->AddToMap(this)) + return false; + + return true; +} + +void AreaTrigger::Update(uint32 p_time) +{ + if (GetDuration() > int32(p_time)) + _duration -= p_time; + else + Remove(); // expired + + WorldObject::Update(p_time); +} + +void AreaTrigger::Remove() +{ + if (IsInWorld()) + { + SendObjectDeSpawnAnim(GetGUID()); + RemoveFromWorld(); + AddObjectToRemoveList(); + } +} diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.h b/src/server/game/Entities/AreaTrigger/AreaTrigger.h new file mode 100644 index 00000000000..cbfa4405b0e --- /dev/null +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITYCORE_AREATRIGGER_H +#define TRINITYCORE_AREATRIGGER_H + +#include "Object.h" + +class Unit; +class SpellInfo; + +class AreaTrigger : public WorldObject, public GridObject<AreaTrigger> +{ + public: + AreaTrigger(); + ~AreaTrigger(); + + void AddToWorld(); + void RemoveFromWorld(); + + bool CreateAreaTrigger(uint32 guidlow, uint32 triggerEntry, Unit* caster, SpellInfo const* spell, Position const& pos); + void Update(uint32 p_time); + void Remove(); + uint32 GetSpellId() const { return GetUInt32Value(AREATRIGGER_SPELLID); } + int32 GetDuration() const { return _duration; } + void SetDuration(int32 newDuration) { _duration = newDuration; } + void Delay(int32 delaytime) { SetDuration(GetDuration() - delaytime); } + + protected: + int32 _duration; +}; +#endif diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index e41426edb3d..9c50cec6ab8 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -31,7 +31,7 @@ Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES), m_type(type m_objectType |= TYPEMASK_CORPSE; m_objectTypeId = TYPEID_CORPSE; - m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_POSITION); + m_updateFlag = UPDATEFLAG_STATIONARY_POSITION; m_valuesCount = CORPSE_END; @@ -114,7 +114,6 @@ void Corpse::SaveToDB() stmt->setString(index++, _ConcatFields(CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END)); // itemCache stmt->setUInt32(index++, GetUInt32Value(CORPSE_FIELD_BYTES_1)); // bytes1 stmt->setUInt32(index++, GetUInt32Value(CORPSE_FIELD_BYTES_2)); // bytes2 - stmt->setUInt32(index++, GetUInt32Value(CORPSE_FIELD_GUILD)); // guildId stmt->setUInt8 (index++, GetUInt32Value(CORPSE_FIELD_FLAGS)); // flags stmt->setUInt8 (index++, GetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS)); // dynFlags stmt->setUInt32(index++, uint32(m_time)); // time @@ -160,10 +159,10 @@ void Corpse::DeleteFromDB(SQLTransaction& trans) bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, guildId, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0 - uint32 ownerGuid = fields[17].GetUInt32(); + uint32 ownerGuid = fields[16].GetUInt32(); float posX = fields[0].GetFloat(); float posY = fields[1].GetFloat(); float posZ = fields[2].GetFloat(); @@ -176,20 +175,18 @@ bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields) _LoadIntoDataField(fields[6].GetCString(), CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END); SetUInt32Value(CORPSE_FIELD_BYTES_1, fields[7].GetUInt32()); SetUInt32Value(CORPSE_FIELD_BYTES_2, fields[8].GetUInt32()); - SetUInt32Value(CORPSE_FIELD_GUILD, fields[9].GetUInt32()); - SetUInt32Value(CORPSE_FIELD_FLAGS, fields[10].GetUInt8()); - SetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS, fields[11].GetUInt8()); + SetUInt32Value(CORPSE_FIELD_FLAGS, fields[9].GetUInt8()); + SetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS, fields[10].GetUInt8()); SetUInt64Value(CORPSE_FIELD_OWNER, MAKE_NEW_GUID(ownerGuid, 0, HIGHGUID_PLAYER)); - m_time = time_t(fields[12].GetUInt32()); + m_time = time_t(fields[11].GetUInt32()); - uint32 instanceId = fields[14].GetUInt32(); - uint32 phaseMask = fields[15].GetUInt32(); + uint32 instanceId = fields[13].GetUInt32(); + //uint32 phaseMask = fields[14].GetUInt32(); // place SetLocationInstanceId(instanceId); SetLocationMapId(mapId); - SetPhaseMask(phaseMask, false); Relocate(posX, posY, posZ, o); if (!IsPositionValid()) diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 52f3a87e7bb..992894a1a3c 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -63,12 +63,12 @@ TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const return NULL; } -bool VendorItemData::RemoveItem(uint32 item_id) +bool VendorItemData::RemoveItem(uint32 item_id, uint8 type) { bool found = false; for (VendorItemList::iterator i = m_items.begin(); i != m_items.end();) { - if ((*i)->item == item_id) + if ((*i)->item == item_id && (*i)->Type == type) { i = m_items.erase(i++); found = true; @@ -79,10 +79,10 @@ bool VendorItemData::RemoveItem(uint32 item_id) return found; } -VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extendedCost) const +VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extendedCost, uint8 type) const { for (VendorItemList::const_iterator i = m_items.begin(); i != m_items.end(); ++i) - if ((*i)->item == item_id && (*i)->ExtendedCost == extendedCost) + if ((*i)->item == item_id && (*i)->ExtendedCost == extendedCost && (*i)->Type == type) return *i; return NULL; } @@ -332,6 +332,7 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) SetName(normalInfo->Name); // at normal entry always SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); + SetFloatValue(UNIT_MOD_CAST_HASTE, 1.0f); SetSpeed(MOVE_WALK, cinfo->speed_walk); SetSpeed(MOVE_RUN, cinfo->speed_run); @@ -613,13 +614,10 @@ void Creature::RegenerateMana() // Combat and any controlled creature if (IsInCombat() || GetCharmerOrOwnerGUID()) { - if (!IsUnderLastManaUseEffect()) - { - float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA); - float Spirit = GetStat(STAT_SPIRIT); + float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA); + float Spirit = GetStat(STAT_SPIRIT); - addvalue = uint32((Spirit / 5.0f + 17.0f) * ManaIncreaseRate); - } + addvalue = uint32((Spirit / 5.0f + 17.0f) * ManaIncreaseRate); } else addvalue = maxValue / 3; @@ -745,11 +743,17 @@ void Creature::Motion_Initialize() GetMotionMaster()->Initialize(); } -bool Creature::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 entry, float x, float y, float z, float ang, CreatureData const* data /*= nullptr*/, uint32 vehId /*= 0*/) +bool Creature::Create(uint32 guidlow, Map* map, uint32 /*phaseMask*/, uint32 entry, float x, float y, float z, float ang, CreatureData const* data /*= nullptr*/, uint32 vehId /*= 0*/) { ASSERT(map); SetMap(map); - SetPhaseMask(phaseMask, false); + + if (data && data->phaseid) + SetInPhase(data->phaseid, false, true); + + if (data && data->phaseGroup) + for (auto ph : GetPhasesForGroup(data->phaseGroup)) + SetInPhase(ph, false, true); CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry); if (!cinfo) @@ -1070,12 +1074,21 @@ void Creature::SelectLevel() // mana uint32 mana = stats->GenerateMana(cInfo); - SetCreateMana(mana); - SetMaxPower(POWER_MANA, mana); // MAX Mana - SetPower(POWER_MANA, mana); - /// @todo set UNIT_FIELD_POWER*, for some creature class case (energy, etc) + switch (getClass()) + { + case CLASS_WARRIOR: + setPowerType(POWER_RAGE); + break; + case CLASS_ROGUE: + setPowerType(POWER_ENERGY); + break; + default: + SetMaxPower(POWER_MANA, mana); // MAX Mana + SetPower(POWER_MANA, mana); + break; + } SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health); SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)mana); @@ -1503,8 +1516,6 @@ void Creature::setDeathState(DeathState s) SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); LoadCreaturesAddon(true); Motion_Initialize(); - if (GetCreatureData() && GetPhaseMask() != GetCreatureData()->phaseMask) - SetPhaseMask(GetCreatureData()->phaseMask, false); Unit::setDeathState(ALIVE); } } @@ -1682,7 +1693,7 @@ SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) if (bcontinue) continue; - if (spellInfo->ManaCost > GetPower(POWER_MANA)) + if (spellInfo->ManaCost > (uint32)GetPower(POWER_MANA)) continue; float range = spellInfo->GetMaxRange(false); float minrange = spellInfo->GetMinRange(false); @@ -1726,7 +1737,7 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim) if (bcontinue) continue; - if (spellInfo->ManaCost > GetPower(POWER_MANA)) + if (spellInfo->ManaCost > (uint32)GetPower(POWER_MANA)) continue; float range = spellInfo->GetMaxRange(true); @@ -2137,11 +2148,6 @@ void Creature::SetInCombatWithZone() } } -uint32 Creature::GetShieldBlockValue() const //dunno mob block value -{ - return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20)); -} - void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time) { m_CreatureSpellCooldowns[spell_id] = end_time; @@ -2454,110 +2460,6 @@ bool Creature::IsDungeonBoss() const return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_DUNGEON_BOSS); } -bool Creature::SetWalk(bool enable) -{ - if (!Unit::SetWalk(enable)) - return false; - - WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_WALK_MODE : SMSG_SPLINE_MOVE_SET_RUN_MODE, 9); - data.append(GetPackGUID()); - SendMessageToSet(&data, false); - return true; -} - -bool Creature::SetDisableGravity(bool disable, bool packetOnly/*=false*/) -{ - //! It's possible only a packet is sent but moveflags are not updated - //! Need more research on this - if (!packetOnly && !Unit::SetDisableGravity(disable)) - return false; - - if (!movespline->Initialized()) - return true; - - WorldPacket data(disable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE, 9); - data.append(GetPackGUID()); - SendMessageToSet(&data, false); - return true; -} - -bool Creature::SetSwim(bool enable) -{ - if (!Unit::SetSwim(enable)) - return false; - - if (!movespline->Initialized()) - return true; - - WorldPacket data(enable ? SMSG_SPLINE_MOVE_START_SWIM : SMSG_SPLINE_MOVE_STOP_SWIM); - data.append(GetPackGUID()); - SendMessageToSet(&data, true); - return true; -} - -bool Creature::SetCanFly(bool enable) -{ - if (!Unit::SetCanFly(enable)) - return false; - - if (!movespline->Initialized()) - return true; - - WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_FLYING : SMSG_SPLINE_MOVE_UNSET_FLYING, 9); - data.append(GetPackGUID()); - SendMessageToSet(&data, false); - return true; -} - -bool Creature::SetWaterWalking(bool enable, bool packetOnly /* = false */) -{ - if (!packetOnly && !Unit::SetWaterWalking(enable)) - return false; - - if (!movespline->Initialized()) - return true; - - WorldPacket data(enable ? SMSG_SPLINE_MOVE_WATER_WALK : SMSG_SPLINE_MOVE_LAND_WALK); - data.append(GetPackGUID()); - SendMessageToSet(&data, true); - return true; -} - -bool Creature::SetFeatherFall(bool enable, bool packetOnly /* = false */) -{ - if (!packetOnly && !Unit::SetFeatherFall(enable)) - return false; - - if (!movespline->Initialized()) - return true; - - WorldPacket data(enable ? SMSG_SPLINE_MOVE_FEATHER_FALL : SMSG_SPLINE_MOVE_NORMAL_FALL); - data.append(GetPackGUID()); - SendMessageToSet(&data, true); - return true; -} - -bool Creature::SetHover(bool enable, bool packetOnly /*= false*/) -{ - if (!packetOnly && !Unit::SetHover(enable)) - return false; - - //! Unconfirmed for players: - if (enable) - SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); - else - RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_HOVER); - - if (!movespline->Initialized()) - return true; - - //! Not always a packet is sent - WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_HOVER : SMSG_SPLINE_MOVE_UNSET_HOVER, 9); - data.append(GetPackGUID()); - SendMessageToSet(&data, false); - return true; -} - float Creature::GetAggroRange(Unit const* target) const { // Determines the aggro range for creatures (usually pets), used mainly for aggressive pet target selection. @@ -2649,7 +2551,7 @@ void Creature::UpdateMovementFlags() } if (!isInAir) - RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING); + SetFall(false); SetSwim(GetCreatureTemplate()->InhabitType & INHABIT_WATER && IsInWater()); } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 8ba5fdcb6fb..f5a0abfc469 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -39,22 +39,23 @@ class WorldSession; enum CreatureFlagsExtra { - CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group - CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) - CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry - CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry - CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block - CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks - CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP - CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature - CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me - CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging) - CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard - CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes - CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills - CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre - CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // Creature is subject to all diminishing returns as player are - CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000 // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB) + CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group + CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) + CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry + CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry + CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block + CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks + CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP + CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature + CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me + CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging) + CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard + CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes + CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills + CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre + CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // Creature is subject to all diminishing returns as player are + CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB) + CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000 // creature ignore pathfinding }; #define CREATURE_FLAG_EXTRA_DB_ALLOWED (CREATURE_FLAG_EXTRA_INSTANCE_BIND | CREATURE_FLAG_EXTRA_CIVILIAN | \ @@ -62,7 +63,7 @@ enum CreatureFlagsExtra CREATURE_FLAG_EXTRA_NO_CRUSH | CREATURE_FLAG_EXTRA_NO_XP_AT_KILL | CREATURE_FLAG_EXTRA_TRIGGER | \ CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \ CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \ - CREATURE_FLAG_EXTRA_GUARD) + CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING) #define MAX_KILL_CREDIT 2 #define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS @@ -82,12 +83,14 @@ struct CreatureTemplate uint32 Modelid3; uint32 Modelid4; std::string Name; + std::string FemaleName; std::string SubName; std::string IconName; uint32 GossipMenuId; uint8 minlevel; uint8 maxlevel; uint32 expansion; + uint32 expansionUnknown; // either 0 or 3, sent to the client / wdb uint32 faction; uint32 npcflag; float speed_walk; @@ -107,7 +110,6 @@ struct CreatureTemplate uint32 dynamicflags; uint32 family; // enum CreatureFamily values (optional) uint32 trainer_type; - uint32 trainer_spell; uint32 trainer_class; uint32 trainer_race; float minrangedmg; @@ -115,6 +117,7 @@ struct CreatureTemplate uint32 rangedattackpower; uint32 type; // enum CreatureType values uint32 type_flags; // enum CreatureTypeFlags mask values + uint32 type_flags2; // unknown enum, only set for 4 creatures (with value 1) uint32 lootid; uint32 pickpocketLootId; uint32 SkinLootId; @@ -130,6 +133,7 @@ struct CreatureTemplate float HoverHeight; float ModHealth; float ModMana; + float ModManaExtra; // Added in 4.x, this value is usually 2 for a small group of creatures with double mana float ModArmor; bool RacialLeader; uint32 questItems[MAX_CREATURE_QUEST_ITEMS]; @@ -202,7 +206,7 @@ struct CreatureBaseStats if (!BaseMana) return 0; - return uint32(ceil(BaseMana * info->ModMana)); + return uint32(ceil(BaseMana * info->ModMana * info->ModManaExtra)); } uint32 GenerateArmor(CreatureTemplate const* info) const @@ -223,6 +227,7 @@ typedef std::unordered_map<uint16, CreatureBaseStats> CreatureBaseStatsContainer struct CreatureLocale { StringVector Name; + StringVector FemaleName; StringVector SubName; }; @@ -252,7 +257,7 @@ struct CreatureData CreatureData() : id(0), mapid(0), phaseMask(0), displayid(0), equipmentId(0), posX(0.0f), posY(0.0f), posZ(0.0f), orientation(0.0f), spawntimesecs(0), spawndist(0.0f), currentwaypoint(0), curhealth(0), curmana(0), movementType(0), - spawnMask(0), npcflag(0), unit_flags(0), dynamicflags(0), dbData(true) { } + spawnMask(0), npcflag(0), unit_flags(0), dynamicflags(0), phaseid(0), phaseGroup(0), dbData(true) { } uint32 id; // entry in creature_template uint16 mapid; uint32 phaseMask; @@ -272,6 +277,8 @@ struct CreatureData uint32 npcflag; uint32 unit_flags; // enum UnitFlags mask values uint32 dynamicflags; + uint32 phaseid; + uint32 phaseGroup; bool dbData; }; @@ -330,13 +337,14 @@ typedef std::unordered_map<uint32, CreatureAddon> CreatureAddonContainer; // Vendors struct VendorItem { - VendorItem(uint32 _item, int32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost) - : item(_item), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost) { } + VendorItem(uint32 _item, int32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost, uint8 _Type) + : item(_item), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost), Type(_Type) { } uint32 item; uint32 maxcount; // 0 for infinity item amount uint32 incrtime; // time for restore items amount if maxcount != 0 uint32 ExtendedCost; + uint8 Type; //helpers bool IsGoldRequired(ItemTemplate const* pProto) const { return pProto->Flags2 & ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD || !ExtendedCost; } @@ -355,13 +363,13 @@ struct VendorItemData return m_items[slot]; } bool Empty() const { return m_items.empty(); } - uint8 GetItemCount() const { return m_items.size(); } - void AddItem(uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost) + uint32 GetItemCount() const { return m_items.size(); } + void AddItem(uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost, uint8 type) { - m_items.push_back(new VendorItem(item, maxcount, ptime, ExtendedCost)); + m_items.push_back(new VendorItem(item, maxcount, ptime, ExtendedCost, type)); } - bool RemoveItem(uint32 item_id); - VendorItem const* FindItemCostPair(uint32 item_id, uint32 extendedCost) const; + bool RemoveItem(uint32 item_id, uint8 type); + VendorItem const* FindItemCostPair(uint32 item_id, uint32 extendedCost, uint8 type) const; void Clear() { for (VendorItemList::const_iterator itr = m_items.begin(); itr != m_items.end(); ++itr) @@ -419,7 +427,7 @@ typedef std::map<uint32, time_t> CreatureSpellCooldowns; // max different by z coordinate for creature aggro reaction #define CREATURE_Z_ATTACK_RANGE 3 -#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY +#define MAX_VENDOR_ITEMS 150 // Limitation in 4.x.x item count in SMSG_LIST_INVENTORY class Creature : public Unit, public GridObject<Creature>, public MapObject { @@ -481,16 +489,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject CreatureAI* AI() const { return (CreatureAI*)i_AI; } - bool SetWalk(bool enable); - bool SetDisableGravity(bool disable, bool packetOnly = false); - bool SetSwim(bool enable); - bool SetCanFly(bool enable); - bool SetWaterWalking(bool enable, bool packetOnly = false); - bool SetFeatherFall(bool enable, bool packetOnly = false); - bool SetHover(bool enable, bool packetOnly = false); - - uint32 GetShieldBlockValue() const; - SpellSchoolMask GetMeleeDamageSchoolMask() const { return m_meleeDamageSchoolMask; } void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); } diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 492d82c5a03..9e72a124ae0 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -371,11 +371,11 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_QUEST_LIST NPC Guid=%u", GUID_LOPART(npcGUID)); } -void PlayerMenu::SendQuestGiverStatus(uint8 questStatus, uint64 npcGUID) const +void PlayerMenu::SendQuestGiverStatus(uint32 questStatus, uint64 npcGUID) const { - WorldPacket data(SMSG_QUESTGIVER_STATUS, 9); + WorldPacket data(SMSG_QUESTGIVER_STATUS, 8 + 4); data << uint64(npcGUID); - data << uint8(questStatus); + data << uint32(questStatus); _session->SendPacket(&data); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_STATUS NPC Guid=%u, status=%u", GUID_LOPART(npcGUID), questStatus); @@ -383,10 +383,14 @@ void PlayerMenu::SendQuestGiverStatus(uint8 questStatus, uint64 npcGUID) const void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, bool activateAccept) const { - std::string questTitle = quest->GetTitle(); - std::string questDetails = quest->GetDetails(); - std::string questObjectives = quest->GetObjectives(); - std::string questEndText = quest->GetEndText(); + std::string questTitle = quest->GetTitle(); + std::string questDetails = quest->GetDetails(); + std::string questObjectives = quest->GetObjectives(); + std::string questEndText = quest->GetEndText(); + std::string questGiverTextWindow = quest->GetQuestGiverTextWindow(); + std::string questGiverTargetName = quest->GetQuestGiverTargetName(); + std::string questTurnTextWindow = quest->GetQuestTurnTextWindow(); + std::string questTurnTargetName = quest->GetQuestTurnTargetName(); int32 locale = _session->GetSessionDbLocaleIndex(); if (locale >= 0) @@ -397,6 +401,10 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, ObjectMgr::GetLocaleString(localeData->Details, locale, questDetails); ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives); ObjectMgr::GetLocaleString(localeData->EndText, locale, questEndText); + ObjectMgr::GetLocaleString(localeData->QuestGiverTextWindow, locale, questGiverTextWindow); + ObjectMgr::GetLocaleString(localeData->QuestGiverTargetName, locale, questGiverTargetName); + ObjectMgr::GetLocaleString(localeData->QuestTurnTextWindow, locale, questTurnTextWindow); + ObjectMgr::GetLocaleString(localeData->QuestTurnTargetName, locale, questTurnTargetName); } } @@ -410,76 +418,23 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, data << questTitle; data << questDetails; data << questObjectives; + data << questGiverTextWindow; // 4.x + data << questGiverTargetName; // 4.x + data << questTurnTextWindow; // 4.x + data << questTurnTargetName; // 4.x + data << uint32(quest->GetQuestGiverPortrait()); // 4.x + data << uint32(quest->GetQuestTurnInPortrait()); // 4.x data << uint8(activateAccept ? 1 : 0); // auto finish data << uint32(quest->GetFlags()); // 3.3.3 questFlags data << uint32(quest->GetSuggestedPlayers()); data << uint8(0); // IsFinished? value is sent back to server in quest accept packet + data << uint8(0); // 4.x FIXME: Starts at AreaTrigger + data << uint32(quest->GetRequiredSpell()); // 4.x - if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) - { - data << uint32(0); // Rewarded chosen items hidden - data << uint32(0); // Rewarded items hidden - data << uint32(0); // Rewarded money hidden - data << uint32(0); // Rewarded XP hidden - } - else - { - data << uint32(quest->GetRewChoiceItemsCount()); - for (uint32 i=0; i < QUEST_REWARD_CHOICES_COUNT; ++i) - { - if (!quest->RewardChoiceItemId[i]) - continue; - - data << uint32(quest->RewardChoiceItemId[i]); - data << uint32(quest->RewardChoiceItemCount[i]); - - if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[i])) - data << uint32(itemTemplate->DisplayInfoID); - else - data << uint32(0x00); - } - - data << uint32(quest->GetRewItemsCount()); - - for (uint32 i=0; i < QUEST_REWARDS_COUNT; ++i) - { - if (!quest->RewardItemId[i]) - continue; - - data << uint32(quest->RewardItemId[i]); - data << uint32(quest->RewardItemIdCount[i]); - - if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RewardItemId[i])) - data << uint32(itemTemplate->DisplayInfoID); - else - data << uint32(0); - } - - data << uint32(quest->GetRewOrReqMoney()); - data << uint32(quest->XPValue(_session->GetPlayer()) * sWorld->getRate(RATE_XP_QUEST)); - } - - // rewarded honor points. Multiply with 10 to satisfy client - data << uint32(10 * quest->CalculateHonorGain(_session->GetPlayer()->GetQuestLevel(quest))); - data << float(0.0f); // unk, honor multiplier? - data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (cast if RewSpellCast == 0) - data << int32(quest->GetRewSpellCast()); // cast spell - data << uint32(quest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles) - data << uint32(quest->GetBonusTalents()); // bonus talents - data << uint32(quest->GetRewArenaPoints()); // reward arena points - data << uint32(0); // unk - - for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - data << uint32(quest->RewardFactionId[i]); - - for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - data << int32(quest->RewardFactionValueId[i]); - - for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - data << int32(quest->RewardFactionValueIdOverride[i]); + quest->BuildExtraQuestInfo(data, _session->GetPlayer()); data << uint32(QUEST_EMOTE_COUNT); - for (uint32 i = 0; i < QUEST_EMOTE_COUNT; ++i) + for (uint8 i = 0; i < QUEST_EMOTE_COUNT; ++i) { data << uint32(quest->DetailsEmote[i]); data << uint32(quest->DetailsEmoteDelay[i]); // DetailsEmoteDelay (in ms) @@ -496,6 +451,10 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const std::string questObjectives = quest->GetObjectives(); std::string questEndText = quest->GetEndText(); std::string questCompletedText = quest->GetCompletedText(); + std::string questGiverTextWindow = quest->GetQuestGiverTextWindow(); + std::string questGiverTargetName = quest->GetQuestGiverTargetName(); + std::string questTurnTextWindow = quest->GetQuestTurnTextWindow(); + std::string questTurnTargetName = quest->GetQuestTurnTargetName(); std::string questObjectiveText[QUEST_OBJECTIVES_COUNT]; for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) @@ -511,6 +470,10 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives); ObjectMgr::GetLocaleString(localeData->EndText, locale, questEndText); ObjectMgr::GetLocaleString(localeData->CompletedText, locale, questCompletedText); + ObjectMgr::GetLocaleString(localeData->QuestGiverTextWindow, locale, questGiverTextWindow); + ObjectMgr::GetLocaleString(localeData->QuestGiverTargetName, locale, questGiverTargetName); + ObjectMgr::GetLocaleString(localeData->QuestTurnTextWindow, locale, questTurnTextWindow); + ObjectMgr::GetLocaleString(localeData->QuestTurnTargetName, locale, questTurnTargetName); for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) ObjectMgr::GetLocaleString(localeData->ObjectiveText[i], locale, questObjectiveText[i]); @@ -550,12 +513,17 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << uint32(quest->GetRewHonorAddition()); data << float(quest->GetRewHonorMultiplier()); data << uint32(quest->GetSrcItemId()); // source item id - data << uint32(quest->GetFlags() & 0xFFFF); // quest flags + data << uint32(quest->GetFlags()); // quest flags + data << uint32(quest->GetMinimapTargetMark()); // minimap target mark (skull, etc. missing enum) data << uint32(quest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles) data << uint32(quest->GetPlayersSlain()); // players slain data << uint32(quest->GetBonusTalents()); // bonus talents - data << uint32(quest->GetRewArenaPoints()); // bonus arena points - data << uint32(0); // review rep show mask + data << uint32(quest->GetRewArenaPoints()); // bonus arena points FIXME: arena points were removed, right? + data << uint32(quest->GetRewardSkillId()); // reward skill id + data << uint32(quest->GetRewardSkillPoints()); // reward skill points + data << uint32(quest->GetRewardReputationMask()); // rep mask (unsure on what it does) + data << uint32(quest->GetQuestGiverPortrait()); // quest giver entry ? + data << uint32(quest->GetQuestTurnInPortrait()); // quest turnin entry ? if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) { @@ -584,7 +552,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid+1 QuestFactionReward.dbc? data << int32(quest->RewardFactionValueId[i]); - for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unk (0) + for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unknown usage data << int32(quest->RewardFactionValueIdOverride[i]); data << uint32(quest->GetPointMapId()); @@ -599,7 +567,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << questObjectives; data << questDetails; data << questEndText; - data << questCompletedText; // display in quest objectives window once all objectives are completed + data << questCompletedText; for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) { @@ -610,7 +578,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << uint32(quest->RequiredNpcOrGoCount[i]); data << uint32(quest->RequiredSourceItemId[i]); - data << uint32(0); // req source count? + data << uint32(quest->RequiredSourceItemCount[i]); } for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) @@ -619,9 +587,30 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << uint32(quest->RequiredItemCount[i]); } + data << uint32(quest->GetRequiredSpell()); // Is it required to be cast, learned or what? + for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) data << questObjectiveText[i]; + for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) + { + data << uint32(quest->RewardCurrencyId[i]); + data << uint32(quest->RewardCurrencyCount[i]); + } + + for (uint32 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i) + { + data << uint32(quest->RequiredCurrencyId[i]); + data << uint32(quest->RequiredCurrencyCount[i]); + } + + data << questGiverTextWindow; + data << questGiverTargetName; + data << questTurnTextWindow; + data << questTurnTargetName; + data << uint32(quest->GetSoundAccept()); + data << uint32(quest->GetSoundTurnIn()); + _session->SendPacket(&data); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u", quest->GetQuestId()); } @@ -630,6 +619,10 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, b { std::string questTitle = quest->GetTitle(); std::string questOfferRewardText = quest->GetOfferRewardText(); + std::string questGiverTextWindow = quest->GetQuestGiverTextWindow(); + std::string questGiverTargetName = quest->GetQuestGiverTargetName(); + std::string questTurnTextWindow = quest->GetQuestTurnTextWindow(); + std::string questTurnTargetName = quest->GetQuestTurnTargetName(); int32 locale = _session->GetSessionDbLocaleIndex(); if (locale >= 0) @@ -638,6 +631,10 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, b { ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); ObjectMgr::GetLocaleString(localeData->OfferRewardText, locale, questOfferRewardText); + ObjectMgr::GetLocaleString(localeData->QuestGiverTextWindow, locale, questGiverTextWindow); + ObjectMgr::GetLocaleString(localeData->QuestGiverTargetName, locale, questGiverTargetName); + ObjectMgr::GetLocaleString(localeData->QuestTurnTextWindow, locale, questTurnTextWindow); + ObjectMgr::GetLocaleString(localeData->QuestTurnTargetName, locale, questTurnTargetName); } } @@ -650,6 +647,13 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, b data << questTitle; data << questOfferRewardText; + data << questGiverTextWindow; + data << questGiverTargetName; + data << questTurnTextWindow; + data << questTurnTargetName; + data << uint32(quest->GetQuestGiverPortrait()); + data << uint32(quest->GetQuestTurnInPortrait()); + data << uint8(enableNext ? 1 : 0); // Auto Finish data << uint32(quest->GetFlags()); // 3.3.3 questFlags data << uint32(quest->GetSuggestedPlayers()); // SuggestedGroupNum @@ -669,52 +673,7 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, b data << uint32(quest->OfferRewardEmote[i]); } - data << uint32(quest->GetRewChoiceItemsCount()); - for (uint32 i=0; i < quest->GetRewChoiceItemsCount(); ++i) - { - data << uint32(quest->RewardChoiceItemId[i]); - data << uint32(quest->RewardChoiceItemCount[i]); - - if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[i])) - data << uint32(itemTemplate->DisplayInfoID); - else - data << uint32(0); - } - - data << uint32(quest->GetRewItemsCount()); - for (uint32 i = 0; i < quest->GetRewItemsCount(); ++i) - { - data << uint32(quest->RewardItemId[i]); - data << uint32(quest->RewardItemIdCount[i]); - - if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RewardItemId[i])) - data << uint32(itemTemplate->DisplayInfoID); - else - data << uint32(0); - } - - data << uint32(quest->GetRewOrReqMoney()); - data << uint32(quest->XPValue(_session->GetPlayer()) * sWorld->getRate(RATE_XP_QUEST)); - - // rewarded honor points. Multiply with 10 to satisfy client - data << uint32(10 * quest->CalculateHonorGain(_session->GetPlayer()->GetQuestLevel(quest))); - data << float(0.0f); // unk, honor multiplier? - data << uint32(0x08); // unused by client? - data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (cast if RewSpellCast == 0) - data << int32(quest->GetRewSpellCast()); // cast spell - data << uint32(0); // unknown - data << uint32(quest->GetBonusTalents()); // bonus talents - data << uint32(quest->GetRewArenaPoints()); // arena points - data << uint32(0); - - for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids - data << uint32(quest->RewardFactionId[i]); - - for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid in QuestFactionReward.dbc (zero based)? - data << int32(quest->RewardFactionValueId[i]); - - for (uint32 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward reputation override? - data << uint32(quest->RewardFactionValueIdOverride[i]); + quest->BuildExtraQuestInfo(data, _session->GetPlayer()); _session->SendPacket(&data); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), quest->GetQuestId()); @@ -784,14 +743,25 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, data << uint32(0); } - if (!canComplete) - data << uint32(0x00); + data << uint32(quest->GetReqCurrencyCount()); + for (int i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i) + { + if (!quest->RequiredCurrencyId[i]) + continue; + + data << uint32(quest->RequiredCurrencyId[i]); + data << uint32(quest->RequiredCurrencyCount[i]); + } + + if (!canComplete) // Experimental; there are 6 similar flags, if any of them + data << uint32(0x00); // of them is 0 player can't complete quest (still unknown meaning) else - data << uint32(0x03); + data << uint32(0x02); data << uint32(0x04); data << uint32(0x08); data << uint32(0x10); + data << uint32(0x40); _session->SendPacket(&data); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), quest->GetQuestId()); diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h index e8fac878409..6d42d7c33f7 100644 --- a/src/server/game/Entities/Creature/GossipDef.h +++ b/src/server/game/Entities/Creature/GossipDef.h @@ -274,7 +274,7 @@ class PlayerMenu /*********************************************************/ /*** QUEST SYSTEM ***/ /*********************************************************/ - void SendQuestGiverStatus(uint8 questStatus, uint64 npcGUID) const; + void SendQuestGiverStatus(uint32 questStatus, uint64 npcGUID) const; void SendQuestGiverQuestList(QEmote const& eEmote, const std::string& Title, uint64 npcGUID); diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index d31117c8381..b982de1289d 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -196,7 +196,8 @@ void TempSummon::InitStats(uint32 duration) if (owner) { - if (uint32 slot = m_Properties->Slot) + int32 slot = m_Properties->Slot; + if (slot > 0) { if (owner->m_SummonSlot[slot] && owner->m_SummonSlot[slot] != GetGUID()) { @@ -268,10 +269,13 @@ void TempSummon::RemoveFromWorld() return; if (m_Properties) - if (uint32 slot = m_Properties->Slot) + { + int32 slot = m_Properties->Slot; + if (slot > 0) if (Unit* owner = GetSummoner()) if (owner->m_SummonSlot[slot] == GetGUID()) owner->m_SummonSlot[slot] = 0; + } //if (GetOwnerGUID()) // TC_LOG_ERROR("entities.unit", "Unit %u has owner guid when removed from world", GetEntry()); @@ -285,6 +289,8 @@ Minion::Minion(SummonPropertiesEntry const* properties, Unit* owner, bool isWorl ASSERT(m_owner); m_unitTypeMask |= UNIT_MASK_MINION; m_followAngle = PET_FOLLOW_ANGLE; + /// @todo: Find correct way + InitCharmInfo(); } void Minion::InitStats(uint32 duration) diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index e008146bb85..00d555c5e9c 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -34,7 +34,7 @@ DynamicObject::DynamicObject(bool isWorldObject) : WorldObject(isWorldObject), m_objectType |= TYPEMASK_DYNAMICOBJECT; m_objectTypeId = TYPEID_DYNAMICOBJECT; - m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_POSITION); + m_updateFlag = UPDATEFLAG_STATIONARY_POSITION; m_valuesCount = DYNAMICOBJECT_END; } @@ -80,29 +80,23 @@ void DynamicObject::RemoveFromWorld() } } -bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type) +bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, SpellInfo const* spell, Position const& pos, float radius, DynamicObjectType type) { SetMap(caster->GetMap()); Relocate(pos); if (!IsPositionValid()) { - TC_LOG_ERROR("misc", "DynamicObject (spell %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", spellId, GetPositionX(), GetPositionY()); + TC_LOG_ERROR("misc", "DynamicObject (spell %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", spell->Id, GetPositionX(), GetPositionY()); return false; } WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetPhaseMask()); - SetEntry(spellId); + SetEntry(spell->Id); SetObjectScale(1); SetUInt64Value(DYNAMICOBJECT_CASTER, caster->GetGUID()); - - // The lower word of DYNAMICOBJECT_BYTES must be 0x0001. This value means that the visual radius will be overriden - // by client for most of the "ground patch" visual effect spells and a few "skyfall" ones like Hurricane. - // If any other value is used, the client will _always_ use the radius provided in DYNAMICOBJECT_RADIUS, but - // precompensation is necessary (eg radius *= 2) for many spells. Anyway, blizz sends 0x0001 for all the spells - // I saw sniffed... - SetByteValue(DYNAMICOBJECT_BYTES, 0, type); - SetUInt32Value(DYNAMICOBJECT_SPELLID, spellId); + SetUInt32Value(DYNAMICOBJECT_BYTES, spell->SpellVisual[0] | (type << 28)); + SetUInt32Value(DYNAMICOBJECT_SPELLID, spell->Id); SetFloatValue(DYNAMICOBJECT_RADIUS, radius); SetUInt32Value(DYNAMICOBJECT_CASTTIME, getMSTime()); diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h index c9fd1d29f8b..ed9b5a3af68 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.h +++ b/src/server/game/Entities/DynamicObject/DynamicObject.h @@ -41,7 +41,7 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject>, publ void AddToWorld(); void RemoveFromWorld(); - bool CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type); + bool CreateDynamicObject(uint32 guidlow, Unit* caster, SpellInfo const* spell, Position const& pos, float radius, DynamicObjectType type); void Update(uint32 p_time); void Remove(); void SetDuration(int32 newDuration); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 0f3e68bb1ae..90f46c4ad86 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -41,7 +41,7 @@ GameObject::GameObject() : WorldObject(false), MapObject(), m_objectType |= TYPEMASK_GAMEOBJECT; m_objectTypeId = TYPEID_GAMEOBJECT; - m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_POSITION | UPDATEFLAG_ROTATION); + m_updateFlag = (UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION); m_valuesCount = GAMEOBJECT_END; m_respawnTime = 0; @@ -167,7 +167,7 @@ void GameObject::RemoveFromWorld() } } -bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit) +bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 /*phaseMask*/, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit) { ASSERT(map); SetMap(map); @@ -180,8 +180,6 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa return false; } - SetPhaseMask(phaseMask, false); - SetZoneScript(); if (m_zoneScript) { @@ -198,7 +196,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa } if (goinfo->type == GAMEOBJECT_TYPE_TRANSPORT) - m_updateFlag = (m_updateFlag | UPDATEFLAG_TRANSPORT) & ~UPDATEFLAG_POSITION; + m_updateFlag |= UPDATEFLAG_TRANSPORT; Object::_Create(guidlow, goinfo->entry, HIGHGUID_GAMEOBJECT); @@ -243,6 +241,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa m_goValue.Building.Health = goinfo->building.intactNumHits + goinfo->building.damagedNumHits; m_goValue.Building.MaxHealth = m_goValue.Building.Health; SetGoAnimProgress(255); + SetUInt32Value(GAMEOBJECT_PARENTROTATION, m_goInfo->building.destructibleData); break; case GAMEOBJECT_TYPE_TRANSPORT: SetUInt32Value(GAMEOBJECT_LEVEL, goinfo->transport.pause); @@ -354,7 +353,7 @@ void GameObject::Update(uint32 diff) SetGoState(GO_STATE_ACTIVE); SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); - UpdateData udata; + UpdateData udata(caster->GetMapId()); WorldPacket packet; BuildValuesUpdateBlockForPlayer(&udata, caster->ToPlayer()); udata.BuildPacket(&packet); @@ -831,6 +830,16 @@ bool GameObject::LoadGameObjectFromDB(uint32 guid, Map* map, bool addToMap) if (!Create(guid, entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, artKit)) return false; + if (data->phaseid) + SetInPhase(data->phaseid, false, true); + + if (data->phaseGroup) + { + // Set the gameobject in all the phases of the phasegroup + for (auto ph : GetPhasesForGroup(data->phaseGroup)) + SetInPhase(ph, false, true); + } + if (data->spawntimesecs >= 0) { m_spawnedByDefault = true; @@ -2081,9 +2090,9 @@ void GameObject::SetDisplayId(uint32 displayid) UpdateModel(); } -void GameObject::SetPhaseMask(uint32 newPhaseMask, bool update) +void GameObject::SetInPhase(uint32 id, bool update, bool apply) { - WorldObject::SetPhaseMask(newPhaseMask, update); + WorldObject::SetInPhase(id, update, apply); if (m_model && m_model->isEnabled()) EnableCollision(true); } @@ -2264,7 +2273,7 @@ void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* *ori = GetOrientation(); } -float GameObject::GetInteractionDistance() +float GameObject::GetInteractionDistance() const { switch (GetGoType()) { diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index f5074e202e9..09c84c71244 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -46,6 +46,7 @@ struct GameObjectTemplate uint32 flags; float size; uint32 questItems[MAX_GAMEOBJECT_QUEST_ITEMS]; + int32 unkInt32; union // different GO types have different data field { //0 GAMEOBJECT_TYPE_DOOR @@ -591,7 +592,7 @@ struct GameObjectData { explicit GameObjectData() : id(0), mapid(0), phaseMask(0), posX(0.0f), posY(0.0f), posZ(0.0f), orientation(0.0f), rotation0(0.0f), rotation1(0.0f), rotation2(0.0f), rotation3(0.0f), spawntimesecs(0), - animprogress(0), go_state(GO_STATE_ACTIVE), spawnMask(0), artKit(0), dbData(true) { } + animprogress(0), go_state(GO_STATE_ACTIVE), spawnMask(0), artKit(0), phaseid(0), phaseGroup(0), dbData(true) { } uint32 id; // entry in gamobject_template uint16 mapid; uint32 phaseMask; @@ -608,6 +609,8 @@ struct GameObjectData GOState go_state; uint8 spawnMask; uint8 artKit; + uint32 phaseid; + uint32 phaseGroup; bool dbData; }; @@ -724,7 +727,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map void SetGoAnimProgress(uint8 animprogress) { SetByteValue(GAMEOBJECT_BYTES_1, 3, animprogress); } static void SetGoArtKit(uint8 artkit, GameObject* go, uint32 lowguid = 0); - void SetPhaseMask(uint32 newPhaseMask, bool update); + void SetInPhase(uint32 id, bool update, bool apply); void EnableCollision(bool enable); void Use(Unit* user); @@ -833,7 +836,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map float GetStationaryZ() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); } float GetStationaryO() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); } - float GetInteractionDistance(); + float GetInteractionDistance() const; void UpdateModelPosition(); @@ -878,6 +881,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map //! Following check does check 3d distance return IsInRange(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), dist2compare); } + GameObjectAI* m_AI; }; #endif diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 09911fc8f57..dcf534690db 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -27,6 +27,7 @@ #include "ScriptMgr.h" #include "ConditionMgr.h" #include "Player.h" +#include "Opcodes.h" #include "WorldSession.h" void AddItemsSetItem(Player* player, Item* item) @@ -213,6 +214,10 @@ bool ItemCanGoIntoBag(ItemTemplate const* pProto, ItemTemplate const* pBagProto) if (!(pProto->BagFamily & BAG_FAMILY_MASK_INSCRIPTION_SUPP)) return false; return true; + case ITEM_SUBCLASS_TACKLE_CONTAINER: + if (!(pProto->BagFamily & BAG_FAMILY_MASK_FISHING_SUPP)) + return false; + return true; default: return false; } @@ -239,7 +244,7 @@ Item::Item() m_objectType |= TYPEMASK_ITEM; m_objectTypeId = TYPEID_ITEM; - m_updateFlag = UPDATEFLAG_LOWGUID; + m_updateFlag = 0; m_valuesCount = ITEM_END; m_slot = 0; @@ -553,46 +558,6 @@ uint32 Item::GetSkill() } } -uint32 Item::GetSpell() -{ - ItemTemplate const* proto = GetTemplate(); - - switch (proto->Class) - { - case ITEM_CLASS_WEAPON: - switch (proto->SubClass) - { - case ITEM_SUBCLASS_WEAPON_AXE: return 196; - case ITEM_SUBCLASS_WEAPON_AXE2: return 197; - case ITEM_SUBCLASS_WEAPON_BOW: return 264; - case ITEM_SUBCLASS_WEAPON_GUN: return 266; - case ITEM_SUBCLASS_WEAPON_MACE: return 198; - case ITEM_SUBCLASS_WEAPON_MACE2: return 199; - case ITEM_SUBCLASS_WEAPON_POLEARM: return 200; - case ITEM_SUBCLASS_WEAPON_SWORD: return 201; - case ITEM_SUBCLASS_WEAPON_SWORD2: return 202; - case ITEM_SUBCLASS_WEAPON_STAFF: return 227; - case ITEM_SUBCLASS_WEAPON_DAGGER: return 1180; - case ITEM_SUBCLASS_WEAPON_THROWN: return 2567; - case ITEM_SUBCLASS_WEAPON_SPEAR: return 3386; - case ITEM_SUBCLASS_WEAPON_CROSSBOW:return 5011; - case ITEM_SUBCLASS_WEAPON_WAND: return 5009; - default: return 0; - } - case ITEM_CLASS_ARMOR: - switch (proto->SubClass) - { - case ITEM_SUBCLASS_ARMOR_CLOTH: return 9078; - case ITEM_SUBCLASS_ARMOR_LEATHER: return 9077; - case ITEM_SUBCLASS_ARMOR_MAIL: return 8737; - case ITEM_SUBCLASS_ARMOR_PLATE: return 750; - case ITEM_SUBCLASS_ARMOR_SHIELD: return 9116; - default: return 0; - } - } - return 0; -} - int32 Item::GenerateItemRandomPropertyId(uint32 item_id) { ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_id); @@ -654,8 +619,8 @@ void Item::SetItemRandomProperties(int32 randomPropId) SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, item_rand->ID); SetState(ITEM_CHANGED, GetOwner()); } - for (uint32 i = PROP_ENCHANTMENT_SLOT_2; i < PROP_ENCHANTMENT_SLOT_2 + 3; ++i) - SetEnchantment(EnchantmentSlot(i), item_rand->enchant_id[i - PROP_ENCHANTMENT_SLOT_2], 0, 0); + for (uint32 i = PROP_ENCHANTMENT_SLOT_1; i < PROP_ENCHANTMENT_SLOT_1 + 3; ++i) + SetEnchantment(EnchantmentSlot(i), item_rand->enchant_id[i - PROP_ENCHANTMENT_SLOT_1], 0, 0); } } else @@ -671,7 +636,7 @@ void Item::SetItemRandomProperties(int32 randomPropId) SetState(ITEM_CHANGED, GetOwner()); } - for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i < PROP_ENCHANTMENT_SLOT_0 + 3; ++i) + for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i <= PROP_ENCHANTMENT_SLOT_4; ++i) SetEnchantment(EnchantmentSlot(i), item_rand->enchant_id[i - PROP_ENCHANTMENT_SLOT_0], 0, 0); } } @@ -791,10 +756,15 @@ bool Item::HasEnchantRequiredSkill(const Player* player) const { // Check all enchants for required skill for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) + { + if (enchant_slot > PRISMATIC_ENCHANTMENT_SLOT && enchant_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id + continue; + if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot))) if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id)) if (enchantEntry->requiredSkill && player->GetSkillValue(enchantEntry->requiredSkill) < enchantEntry->requiredSkillValue) return false; + } return true; } @@ -805,10 +775,15 @@ uint32 Item::GetEnchantRequiredLevel() const // Check all enchants for required level for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) + { + if (enchant_slot > PRISMATIC_ENCHANTMENT_SLOT && enchant_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id + continue; + if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot))) if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id)) if (enchantEntry->requiredLevel > level) level = enchantEntry->requiredLevel; + } return level; } @@ -817,10 +792,16 @@ bool Item::IsBoundByEnchant() const { // Check all enchants for soulbound for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) + { + if (enchant_slot > PRISMATIC_ENCHANTMENT_SLOT && enchant_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id + continue; + if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot))) if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id)) if (enchantEntry->slot & ENCHANTMENT_CAN_SOULBOUND) return true; + } + return false; } @@ -828,15 +809,15 @@ InventoryResult Item::CanBeMergedPartlyWith(ItemTemplate const* proto) const { // not allow merge looting currently items if (m_lootGenerated) - return EQUIP_ERR_ALREADY_LOOTED; + return EQUIP_ERR_LOOT_GONE; // check item type if (GetEntry() != proto->ItemId) - return EQUIP_ERR_ITEM_CANT_STACK; + return EQUIP_ERR_CANT_STACK; // check free space (full stacks can't be target of merge if (GetCount() >= proto->GetMaxStackSize()) - return EQUIP_ERR_ITEM_CANT_STACK; + return EQUIP_ERR_CANT_STACK; return EQUIP_ERR_OK; } @@ -848,8 +829,8 @@ bool Item::IsFitToSpellRequirements(SpellInfo const* spellInfo) const if (spellInfo->EquippedItemClass != -1) // -1 == any item class { // Special case - accept vellum for armor/weapon requirements - if ((spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && proto->IsArmorVellum()) - ||(spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && proto->IsWeaponVellum())) + if ((spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR || + spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON) && proto->IsVellum()) if (spellInfo->IsAbilityOfSkillType(SKILL_ENCHANTING)) // only for enchanting spells return true; @@ -1227,6 +1208,305 @@ bool Item::CheckSoulboundTradeExpire() return false; } +bool Item::CanBeTransmogrified() const +{ + ItemTemplate const* proto = GetTemplate(); + + if (!proto) + return false; + + if (proto->Quality == ITEM_QUALITY_LEGENDARY) + return false; + + if (proto->Class != ITEM_CLASS_ARMOR && + proto->Class != ITEM_CLASS_WEAPON) + return false; + + if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE) + return false; + + if (proto->Flags2 & ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG) + return false; + + if (!HasStats()) + return false; + + return true; +} + +bool Item::CanTransmogrify() const +{ + ItemTemplate const* proto = GetTemplate(); + + if (!proto) + return false; + + if (proto->Flags2 & ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG) + return false; + + if (proto->Quality == ITEM_QUALITY_LEGENDARY) + return false; + + if (proto->Class != ITEM_CLASS_ARMOR && + proto->Class != ITEM_CLASS_WEAPON) + return false; + + if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE) + return false; + + if (proto->Flags2 & ITEM_FLAGS_EXTRA_CAN_TRANSMOG) + return true; + + if (!HasStats()) + return false; + + return true; +} + +bool Item::CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* transmogrifier) +{ + if (!transmogrifier || !transmogrified) + return false; + + ItemTemplate const* proto1 = transmogrifier->GetTemplate(); // source + ItemTemplate const* proto2 = transmogrified->GetTemplate(); // dest + + if (proto1->ItemId == proto2->ItemId) + return false; + + if (!transmogrified->CanTransmogrify() || !transmogrifier->CanBeTransmogrified()) + return false; + + if (proto1->InventoryType == INVTYPE_BAG || + proto1->InventoryType == INVTYPE_RELIC || + proto1->InventoryType == INVTYPE_BODY || + proto1->InventoryType == INVTYPE_FINGER || + proto1->InventoryType == INVTYPE_TRINKET || + proto1->InventoryType == INVTYPE_AMMO || + proto1->InventoryType == INVTYPE_QUIVER) + return false; + + if (proto1->SubClass != proto2->SubClass && (proto1->Class != ITEM_CLASS_WEAPON || !proto2->IsRangedWeapon() || !proto1->IsRangedWeapon())) + return false; + + if (proto1->InventoryType != proto2->InventoryType && + (proto1->Class != ITEM_CLASS_WEAPON || (proto2->InventoryType != INVTYPE_WEAPONMAINHAND && proto2->InventoryType != INVTYPE_WEAPONOFFHAND)) && + (proto1->Class != ITEM_CLASS_ARMOR || (proto1->InventoryType != INVTYPE_CHEST && proto2->InventoryType != INVTYPE_ROBE && proto1->InventoryType != INVTYPE_ROBE && proto2->InventoryType != INVTYPE_CHEST))) + return false; + + return true; +} + +bool Item::HasStats() const +{ + if (GetItemRandomPropertyId() != 0) + return true; + + ItemTemplate const* proto = GetTemplate(); + for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + if (proto->ItemStat[i].ItemStatValue != 0) + return true; + + return false; +} + +// used by mail items, transmog cost, stationeryinfo and others +uint32 Item::GetSellPrice(ItemTemplate const* proto, bool& normalSellPrice) +{ + normalSellPrice = true; + + if (proto->Flags2 & ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE) + { + return proto->BuyPrice; + } + else + { + ImportPriceQualityEntry const* qualityPrice = sImportPriceQualityStore.LookupEntry(proto->Quality + 1); + ItemPriceBaseEntry const* basePrice = sItemPriceBaseStore.LookupEntry(proto->ItemLevel); + + if (!qualityPrice || !basePrice) + return 0; + + float qualityFactor = qualityPrice->Factor; + float baseFactor = 0.0f; + + uint32 inventoryType = proto->InventoryType; + + if (inventoryType == INVTYPE_WEAPON || + inventoryType == INVTYPE_2HWEAPON || + inventoryType == INVTYPE_WEAPONMAINHAND || + inventoryType == INVTYPE_WEAPONOFFHAND || + inventoryType == INVTYPE_RANGED || + inventoryType == INVTYPE_THROWN || + inventoryType == INVTYPE_RANGEDRIGHT) + baseFactor = basePrice->WeaponFactor; + else + baseFactor = basePrice->ArmorFactor; + + if (inventoryType == INVTYPE_ROBE) + inventoryType = INVTYPE_CHEST; + + float typeFactor = 0.0f; + int8 weapType = -1; + + switch (inventoryType) + { + case INVTYPE_HEAD: + case INVTYPE_SHOULDERS: + case INVTYPE_CHEST: + case INVTYPE_WAIST: + case INVTYPE_LEGS: + case INVTYPE_FEET: + case INVTYPE_WRISTS: + case INVTYPE_HANDS: + case INVTYPE_CLOAK: + { + ImportPriceArmorEntry const* armorPrice = sImportPriceArmorStore.LookupEntry(inventoryType); + if (!armorPrice) + return 0; + + switch (proto->SubClass) + { + case ITEM_SUBCLASS_ARMOR_MISCELLANEOUS: + case ITEM_SUBCLASS_ARMOR_CLOTH: + typeFactor = armorPrice->ClothFactor; + break; + case ITEM_SUBCLASS_ARMOR_LEATHER: + typeFactor = armorPrice->LeatherFactor; + break; + case ITEM_SUBCLASS_ARMOR_MAIL: + typeFactor = armorPrice->MailFactor; + break; + case ITEM_SUBCLASS_ARMOR_PLATE: + typeFactor = armorPrice->PlateFactor; + break; + default: + return 0; + } + + break; + } + case INVTYPE_SHIELD: + { + ImportPriceShieldEntry const* shieldPrice = sImportPriceShieldStore.LookupEntry(1); // it only has two rows, it's unclear which is the one used + if (!shieldPrice) + return 0; + + typeFactor = shieldPrice->Factor; + break; + } + case INVTYPE_WEAPONMAINHAND: + weapType = 0; + break; + case INVTYPE_WEAPONOFFHAND: + weapType = 1; + break; + case INVTYPE_WEAPON: + weapType = 2; + break; + case INVTYPE_2HWEAPON: + weapType = 3; + break; + case INVTYPE_RANGED: + case INVTYPE_RANGEDRIGHT: + case INVTYPE_RELIC: + weapType = 4; + break; + default: + return proto->BuyPrice; + } + + if (weapType != -1) + { + ImportPriceWeaponEntry const* weaponPrice = sImportPriceWeaponStore.LookupEntry(weapType + 1); + if (!weaponPrice) + return 0; + + typeFactor = weaponPrice->Factor; + } + + normalSellPrice = false; + return uint32(qualityFactor * proto->Unk430_2 * proto->Unk430_1 * typeFactor * baseFactor); + } +} + +uint32 Item::GetSpecialPrice(ItemTemplate const* proto, uint32 minimumPrice /*= 10000*/) +{ + uint32 cost = 0; + + if (proto->Flags2 & ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE) + cost = proto->SellPrice; + else + { + bool normalPrice; + cost = Item::GetSellPrice(proto, normalPrice); + + if (!normalPrice) + { + if (proto->BuyCount <= 1) + { + ItemClassEntry const* classEntry = sItemClassStore.LookupEntry(proto->Class); + if (classEntry) + cost *= classEntry->PriceFactor; + else + cost = 0; + } + else + cost /= 4 * proto->BuyCount; + } + else + cost = proto->SellPrice; + } + + if (cost < minimumPrice) + cost = minimumPrice; + + return cost; +} + +int32 Item::GetReforgableStat(ItemModType statType) const +{ + ItemTemplate const* proto = GetTemplate(); + for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + if (ItemModType(proto->ItemStat[i].ItemStatType) == statType) + return proto->ItemStat[i].ItemStatValue; + + int32 randomPropId = GetItemRandomPropertyId(); + if (!randomPropId) + return 0; + + if (randomPropId < 0) + { + ItemRandomSuffixEntry const* randomSuffix = sItemRandomSuffixStore.LookupEntry(-randomPropId); + if (!randomSuffix) + return 0; + + for (uint32 e = PROP_ENCHANTMENT_SLOT_0; e <= PROP_ENCHANTMENT_SLOT_4; ++e) + if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(GetEnchantmentId(EnchantmentSlot(e)))) + for (uint32 f = 0; f < MAX_ITEM_ENCHANTMENT_EFFECTS; ++f) + if (enchant->type[f] == ITEM_ENCHANTMENT_TYPE_STAT && ItemModType(enchant->spellid[f]) == statType) + for (int k = 0; k < 5; ++k) + if (randomSuffix->enchant_id[k] == enchant->ID) + return int32((randomSuffix->prefix[k] * GetItemSuffixFactor()) / 10000); + } + else + { + ItemRandomPropertiesEntry const* randomProp = sItemRandomPropertiesStore.LookupEntry(randomPropId); + if (!randomProp) + return 0; + + for (uint32 e = PROP_ENCHANTMENT_SLOT_0; e <= PROP_ENCHANTMENT_SLOT_4; ++e) + if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(GetEnchantmentId(EnchantmentSlot(e)))) + for (uint32 f = 0; f < MAX_ITEM_ENCHANTMENT_EFFECTS; ++f) + if (enchant->type[f] == ITEM_ENCHANTMENT_TYPE_STAT && ItemModType(enchant->spellid[f]) == statType) + for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k) + if (randomProp->enchant_id[k] == enchant->ID) + return int32(enchant->amount[k]); + } + + return 0; +} + void Item::ItemContainerSaveLootToDB() { // Saves the money and item loot associated with an openable item to the DB diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index a65579cc134..ebd66a64838 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -38,95 +38,99 @@ struct ItemSetEffect enum InventoryResult { - EQUIP_ERR_OK = 0, - EQUIP_ERR_CANT_EQUIP_LEVEL_I = 1, - EQUIP_ERR_CANT_EQUIP_SKILL = 2, - EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT = 3, - EQUIP_ERR_BAG_FULL = 4, - EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG = 5, - EQUIP_ERR_CANT_TRADE_EQUIP_BAGS = 6, - EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE = 7, - EQUIP_ERR_NO_REQUIRED_PROFICIENCY = 8, - EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE = 9, - EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM = 10, - EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM2 = 11, - EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE2 = 12, - EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED = 13, - EQUIP_ERR_CANT_DUAL_WIELD = 14, - EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG = 15, - EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG2 = 16, - EQUIP_ERR_CANT_CARRY_MORE_OF_THIS = 17, - EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE3 = 18, - EQUIP_ERR_ITEM_CANT_STACK = 19, - EQUIP_ERR_ITEM_CANT_BE_EQUIPPED = 20, - EQUIP_ERR_ITEMS_CANT_BE_SWAPPED = 21, - EQUIP_ERR_SLOT_IS_EMPTY = 22, - EQUIP_ERR_ITEM_NOT_FOUND = 23, - EQUIP_ERR_CANT_DROP_SOULBOUND = 24, - EQUIP_ERR_OUT_OF_RANGE = 25, - EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT = 26, - EQUIP_ERR_COULDNT_SPLIT_ITEMS = 27, - EQUIP_ERR_MISSING_REAGENT = 28, - EQUIP_ERR_NOT_ENOUGH_MONEY = 29, - EQUIP_ERR_NOT_A_BAG = 30, - EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS = 31, - EQUIP_ERR_DONT_OWN_THAT_ITEM = 32, - EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER = 33, - EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT = 34, - EQUIP_ERR_TOO_FAR_AWAY_FROM_BANK = 35, - EQUIP_ERR_ITEM_LOCKED = 36, - EQUIP_ERR_YOU_ARE_STUNNED = 37, - EQUIP_ERR_YOU_ARE_DEAD = 38, - EQUIP_ERR_CANT_DO_RIGHT_NOW = 39, - EQUIP_ERR_INT_BAG_ERROR = 40, - EQUIP_ERR_CAN_EQUIP_ONLY1_BOLT = 41, - EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH = 42, - EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED = 43, - EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED = 44, - EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED = 45, - EQUIP_ERR_BOUND_CANT_BE_WRAPPED = 46, - EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED = 47, - EQUIP_ERR_BAGS_CANT_BE_WRAPPED = 48, - EQUIP_ERR_ALREADY_LOOTED = 49, - EQUIP_ERR_INVENTORY_FULL = 50, - EQUIP_ERR_BANK_FULL = 51, - EQUIP_ERR_ITEM_IS_CURRENTLY_SOLD_OUT = 52, - EQUIP_ERR_BAG_FULL3 = 53, - EQUIP_ERR_ITEM_NOT_FOUND2 = 54, - EQUIP_ERR_ITEM_CANT_STACK2 = 55, - EQUIP_ERR_BAG_FULL4 = 56, - EQUIP_ERR_ITEM_SOLD_OUT = 57, - EQUIP_ERR_OBJECT_IS_BUSY = 58, - EQUIP_ERR_NONE = 59, - EQUIP_ERR_NOT_IN_COMBAT = 60, - EQUIP_ERR_NOT_WHILE_DISARMED = 61, - EQUIP_ERR_BAG_FULL6 = 62, - EQUIP_ERR_CANT_EQUIP_RANK = 63, - EQUIP_ERR_CANT_EQUIP_REPUTATION = 64, - EQUIP_ERR_TOO_MANY_SPECIAL_BAGS = 65, - EQUIP_ERR_LOOT_CANT_LOOT_THAT_NOW = 66, - EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE = 67, - EQUIP_ERR_VENDOR_MISSING_TURNINS = 68, - EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS = 69, - EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS = 70, - EQUIP_ERR_ITEM_MAX_COUNT_SOCKETED = 71, - EQUIP_ERR_MAIL_BOUND_ITEM = 72, - EQUIP_ERR_NO_SPLIT_WHILE_PROSPECTING = 73, - EQUIP_ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED = 75, - EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED = 76, - EQUIP_ERR_TOO_MUCH_GOLD = 77, - EQUIP_ERR_NOT_DURING_ARENA_MATCH = 78, - EQUIP_ERR_CANNOT_TRADE_THAT = 79, - EQUIP_ERR_PERSONAL_ARENA_RATING_TOO_LOW = 80, - EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM = 81, - EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS = 82, - // no output = 83, - EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED = 84, - EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED = 85, - EQUIP_ERR_SCALING_STAT_ITEM_LEVEL_EXCEEDED = 86, - EQUIP_ERR_PURCHASE_LEVEL_TOO_LOW = 87, - EQUIP_ERR_CANT_EQUIP_NEED_TALENT = 88, - EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED = 89 + EQUIP_ERR_OK = 0, + EQUIP_ERR_CANT_EQUIP_LEVEL_I = 1, // You must reach level %d to use that item. + EQUIP_ERR_CANT_EQUIP_SKILL = 2, // You aren't skilled enough to use that item. + EQUIP_ERR_WRONG_SLOT = 3, // That item does not go in that slot. + EQUIP_ERR_BAG_FULL = 4, // That bag is full. + EQUIP_ERR_BAG_IN_BAG = 5, // Can't put non-empty bags in other bags. + EQUIP_ERR_TRADE_EQUIPPED_BAG = 6, // You can't trade equipped bags. + EQUIP_ERR_AMMO_ONLY = 7, // Only ammo can go there. + EQUIP_ERR_PROFICIENCY_NEEDED = 8, // You do not have the required proficiency for that item. + EQUIP_ERR_NO_SLOT_AVAILABLE = 9, // No equipment slot is available for that item. + EQUIP_ERR_CANT_EQUIP_EVER = 10, // You can never use that item. + EQUIP_ERR_CANT_EQUIP_EVER_2 = 11, // You can never use that item. + EQUIP_ERR_NO_SLOT_AVAILABLE_2 = 12, // No equipment slot is available for that item. + EQUIP_ERR_2HANDED_EQUIPPED = 13, // Cannot equip that with a two-handed weapon. + EQUIP_ERR_2HSKILLNOTFOUND = 14, // You cannot dual-wield + EQUIP_ERR_WRONG_BAG_TYPE = 15, // That item doesn't go in that container. + EQUIP_ERR_WRONG_BAG_TYPE_2 = 16, // That item doesn't go in that container. + EQUIP_ERR_ITEM_MAX_COUNT = 17, // You can't carry any more of those items. + EQUIP_ERR_NO_SLOT_AVAILABLE_3 = 18, // No equipment slot is available for that item. + EQUIP_ERR_CANT_STACK = 19, // This item cannot stack. + EQUIP_ERR_NOT_EQUIPPABLE = 20, // This item cannot be equipped. + EQUIP_ERR_CANT_SWAP = 21, // These items can't be swapped. + EQUIP_ERR_SLOT_EMPTY = 22, // That slot is empty. + EQUIP_ERR_ITEM_NOT_FOUND = 23, // The item was not found. + EQUIP_ERR_DROP_BOUND_ITEM = 24, // You can't drop a soulbound item. + EQUIP_ERR_OUT_OF_RANGE = 25, // Out of range. + EQUIP_ERR_TOO_FEW_TO_SPLIT = 26, // Tried to split more than number in stack. + EQUIP_ERR_SPLIT_FAILED = 27, // Couldn't split those items. + EQUIP_ERR_SPELL_FAILED_REAGENTS_GENERIC = 28, // Missing reagent + EQUIP_ERR_NOT_ENOUGH_MONEY = 29, // You don't have enough money. + EQUIP_ERR_NOT_A_BAG = 30, // Not a bag. + EQUIP_ERR_DESTROY_NONEMPTY_BAG = 31, // You can only do that with empty bags. + EQUIP_ERR_NOT_OWNER = 32, // You don't own that item. + EQUIP_ERR_ONLY_ONE_QUIVER = 33, // You can only equip one quiver. + EQUIP_ERR_NO_BANK_SLOT = 34, // You must purchase that bag slot first + EQUIP_ERR_NO_BANK_HERE = 35, // You are too far away from a bank. + EQUIP_ERR_ITEM_LOCKED = 36, // Item is locked. + EQUIP_ERR_GENERIC_STUNNED = 37, // You are stunned + EQUIP_ERR_PLAYER_DEAD = 38, // You can't do that when you're dead. + EQUIP_ERR_CLIENT_LOCKED_OUT = 39, // You can't do that right now. + EQUIP_ERR_INTERNAL_BAG_ERROR = 40, // Internal Bag Error + EQUIP_ERR_ONLY_ONE_BOLT = 41, // You can only equip one quiver. + EQUIP_ERR_ONLY_ONE_AMMO = 42, // You can only equip one ammo pouch. + EQUIP_ERR_CANT_WRAP_STACKABLE = 43, // Stackable items can't be wrapped. + EQUIP_ERR_CANT_WRAP_EQUIPPED = 44, // Equipped items can't be wrapped. + EQUIP_ERR_CANT_WRAP_WRAPPED = 45, // Wrapped items can't be wrapped. + EQUIP_ERR_CANT_WRAP_BOUND = 46, // Bound items can't be wrapped. + EQUIP_ERR_CANT_WRAP_UNIQUE = 47, // Unique items can't be wrapped. + EQUIP_ERR_CANT_WRAP_BAGS = 48, // Bags can't be wrapped. + EQUIP_ERR_LOOT_GONE = 49, // Already looted + EQUIP_ERR_INV_FULL = 50, // Inventory is full. + EQUIP_ERR_BANK_FULL = 51, // Your bank is full + EQUIP_ERR_VENDOR_SOLD_OUT = 52, // That item is currently sold out. + EQUIP_ERR_BAG_FULL_2 = 53, // That bag is full. + EQUIP_ERR_ITEM_NOT_FOUND_2 = 54, // The item was not found. + EQUIP_ERR_CANT_STACK_2 = 55, // This item cannot stack. + EQUIP_ERR_BAG_FULL_3 = 56, // That bag is full. + EQUIP_ERR_VENDOR_SOLD_OUT_2 = 57, // That item is currently sold out. + EQUIP_ERR_OBJECT_IS_BUSY = 58, // That object is busy. + EQUIP_ERR_CANT_BE_DISENCHANTED = 59, + EQUIP_ERR_NOT_IN_COMBAT = 60, // You can't do that while in combat + EQUIP_ERR_NOT_WHILE_DISARMED = 61, // You can't do that while disarmed + EQUIP_ERR_BAG_FULL_4 = 62, // That bag is full. + EQUIP_ERR_CANT_EQUIP_RANK = 63, // You don't have the required rank for that item + EQUIP_ERR_CANT_EQUIP_REPUTATION = 64, // You don't have the required reputation for that item + EQUIP_ERR_TOO_MANY_SPECIAL_BAGS = 65, // You cannot equip another bag of that type + EQUIP_ERR_LOOT_CANT_LOOT_THAT_NOW = 66, // You can't loot that item now. + EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE = 67, // You cannot equip more than one of those. + EQUIP_ERR_VENDOR_MISSING_TURNINS = 68, // You do not have the required items for that purchase + EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS = 69, // You don't have enough honor points + EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS = 70, // You don't have enough arena points + EQUIP_ERR_ITEM_MAX_COUNT_SOCKETED = 71, // You have the maximum number of those gems in your inventory or socketed into items. + EQUIP_ERR_MAIL_BOUND_ITEM = 72, // You can't mail soulbound items. + EQUIP_ERR_INTERNAL_BAG_ERROR_2 = 73, // Internal Bag Error + EQUIP_ERR_BAG_FULL_5 = 74, // That bag is full. + EQUIP_ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED = 75, // You have the maximum number of those gems socketed into equipped items. + EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED = 76, // You cannot socket more than one of those gems into a single item. + EQUIP_ERR_TOO_MUCH_GOLD = 77, // At gold limit + EQUIP_ERR_NOT_DURING_ARENA_MATCH = 78, // You can't do that while in an arena match + EQUIP_ERR_TRADE_BOUND_ITEM = 79, // You can't trade a soulbound item. + EQUIP_ERR_CANT_EQUIP_RATING = 80, // You don't have the personal, team, or battleground rating required to buy that item + EQUIP_ERR_NO_OUTPUT = 81, + EQUIP_ERR_NOT_SAME_ACCOUNT = 82, // Account-bound items can only be given to your own characters. + EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS = 84, // You can only carry %d %s + EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED_IS = 85, // You can only equip %d |4item:items in the %s category + EQUIP_ERR_SCALING_STAT_ITEM_LEVEL_EXCEEDED = 86, // Your level is too high to use that item + EQUIP_ERR_PURCHASE_LEVEL_TOO_LOW = 87, // You must reach level %d to purchase that item. + EQUIP_ERR_CANT_EQUIP_NEED_TALENT = 88, // You do not have the required talent to equip that. + EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS = 89, // You can only equip %d |4item:items in the %s category + EQUIP_ERR_SHAPESHIFT_FORM_CANNOT_EQUIP = 90, // Cannot equip item in this form + EQUIP_ERR_ITEM_INVENTORY_FULL_SATCHEL = 91, // Your inventory is full. Your satchel has been delivered to your mailbox. + EQUIP_ERR_SCALING_STAT_ITEM_LEVEL_TOO_LOW = 92, // Your level is too low to use that item + EQUIP_ERR_CANT_BUY_QUANTITY = 93, // You can't buy the specified quantity of that item. }; enum BuyResult @@ -162,14 +166,17 @@ enum EnchantmentSlot SOCK_ENCHANTMENT_SLOT_3 = 4, BONUS_ENCHANTMENT_SLOT = 5, PRISMATIC_ENCHANTMENT_SLOT = 6, // added at apply special permanent enchantment - MAX_INSPECTED_ENCHANTMENT_SLOT = 7, - - PROP_ENCHANTMENT_SLOT_0 = 7, // used with RandomSuffix - PROP_ENCHANTMENT_SLOT_1 = 8, // used with RandomSuffix - PROP_ENCHANTMENT_SLOT_2 = 9, // used with RandomSuffix and RandomProperty - PROP_ENCHANTMENT_SLOT_3 = 10, // used with RandomProperty - PROP_ENCHANTMENT_SLOT_4 = 11, // used with RandomProperty - MAX_ENCHANTMENT_SLOT = 12 + //TODO: 7, + REFORGE_ENCHANTMENT_SLOT = 8, + TRANSMOGRIFY_ENCHANTMENT_SLOT = 9, + MAX_INSPECTED_ENCHANTMENT_SLOT = 10, + + PROP_ENCHANTMENT_SLOT_0 = 10, // used with RandomSuffix + PROP_ENCHANTMENT_SLOT_1 = 11, // used with RandomSuffix + PROP_ENCHANTMENT_SLOT_2 = 12, // used with RandomSuffix and RandomProperty + PROP_ENCHANTMENT_SLOT_3 = 13, // used with RandomProperty + PROP_ENCHANTMENT_SLOT_4 = 14, // used with RandomProperty + MAX_ENCHANTMENT_SLOT = 15 }; #define MAX_VISIBLE_ITEM_OFFSET 2 // 2 fields per visible item (entry+enchantment) @@ -224,6 +231,7 @@ class Item : public Object void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, val); } bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND); } bool IsBoundAccountWide() const { return (GetTemplate()->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT) != 0; } + bool IsBattlenetAccountBound() const { return (GetTemplate()->Flags2 & ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND) != 0; } bool IsBindedNotWith(Player const* player) const; bool IsBoundByEnchant() const; virtual void SaveToDB(SQLTransaction& trans); @@ -281,7 +289,6 @@ class Item : public Object bool IsEquipped() const; uint32 GetSkill(); - uint32 GetSpell(); // RandomPropertyId (signed but stored as unsigned) int32 GetItemRandomPropertyId() const { return GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID); } @@ -326,10 +333,11 @@ class Item : public Object bool hasQuest(uint32 quest_id) const { return GetTemplate()->StartQuest == quest_id; } bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; } + bool HasStats() const; bool IsPotion() const { return GetTemplate()->IsPotion(); } - bool IsWeaponVellum() const { return GetTemplate()->IsWeaponVellum(); } - bool IsArmorVellum() const { return GetTemplate()->IsArmorVellum(); } + bool IsVellum() const { return GetTemplate()->IsVellum(); } bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); } + bool IsRangedWeapon() const { return GetTemplate()->IsRangedWeapon(); } // Item Refund system void SetNotRefundable(Player* owner, bool changestate = true, SQLTransaction* trans = NULL); @@ -353,6 +361,24 @@ class Item : public Object void BuildUpdate(UpdateDataMapType&); uint32 GetScriptId() const { return GetTemplate()->ScriptId; } + + bool CanBeTransmogrified() const; + bool CanTransmogrify() const; + static bool CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* transmogrifier); + static uint32 GetSpecialPrice(ItemTemplate const* proto, uint32 minimumPrice = 10000); + uint32 GetSpecialPrice(uint32 minimumPrice = 10000) const { return Item::GetSpecialPrice(GetTemplate(), minimumPrice); } + + uint32 GetVisibleEntry() const + { + if (uint32 transmogrification = GetEnchantmentId(TRANSMOGRIFY_ENCHANTMENT_SLOT)) + return transmogrification; + return GetEntry(); + } + + static uint32 GetSellPrice(ItemTemplate const* proto, bool& success); + + int32 GetReforgableStat(ItemModType statType) const; + private: std::string m_text; uint8 m_slot; diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h index 7e17fd6ae4d..e470afac1ab 100644 --- a/src/server/game/Entities/Item/ItemPrototype.h +++ b/src/server/game/Entities/Item/ItemPrototype.h @@ -59,18 +59,23 @@ enum ItemModType ITEM_MOD_EXPERTISE_RATING = 37, ITEM_MOD_ATTACK_POWER = 38, ITEM_MOD_RANGED_ATTACK_POWER = 39, - //ITEM_MOD_FERAL_ATTACK_POWER = 40, not in 3.3 - ITEM_MOD_SPELL_HEALING_DONE = 41, // deprecated - ITEM_MOD_SPELL_DAMAGE_DONE = 42, // deprecated ITEM_MOD_MANA_REGENERATION = 43, ITEM_MOD_ARMOR_PENETRATION_RATING = 44, ITEM_MOD_SPELL_POWER = 45, ITEM_MOD_HEALTH_REGEN = 46, ITEM_MOD_SPELL_PENETRATION = 47, - ITEM_MOD_BLOCK_VALUE = 48 + ITEM_MOD_BLOCK_VALUE = 48, + ITEM_MOD_MASTERY_RATING = 49, + ITEM_MOD_EXTRA_ARMOR = 50, + ITEM_MOD_FIRE_RESISTANCE = 51, + ITEM_MOD_FROST_RESISTANCE = 52, + ITEM_MOD_HOLY_RESISTANCE = 53, + ITEM_MOD_SHADOW_RESISTANCE = 54, + ITEM_MOD_NATURE_RESISTANCE = 55, + ITEM_MOD_ARCANE_RESISTANCE = 56, }; -#define MAX_ITEM_MOD 49 +#define MAX_ITEM_MOD 57 enum ItemSpelltriggerType { @@ -138,7 +143,7 @@ enum ItemProtoFlags ITEM_PROTO_FLAG_TRIGGERED_CAST = 0x10000000, // Spell is cast with triggered flag ITEM_PROTO_FLAG_MILLABLE = 0x20000000, // Item can be milled ITEM_PROTO_FLAG_UNK11 = 0x40000000, // ? - ITEM_PROTO_FLAG_UNK12 = 0x80000000 // ? + ITEM_PROTO_FLAG_BOP_TRADEABLE = 0x80000000 // bound item that can be traded }; enum ItemFieldFlags @@ -184,7 +189,13 @@ enum ItemFlagsExtra ITEM_FLAGS_EXTRA_HORDE_ONLY = 0x00000001, ITEM_FLAGS_EXTRA_ALLIANCE_ONLY = 0x00000002, ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD = 0x00000004, // when item uses extended cost, gold is also required - ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED = 0x00000100 + ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED = 0x00000100, + ITEM_FLAGS_EXTRA_CASTER_WEAPON = 0x00000200, + ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE = 0x00004000, + ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND = 0x00020000, + ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG = 0x00200000, + ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG = 0x00400000, + ITEM_FLAGS_EXTRA_CAN_TRANSMOG = 0x00800000, }; enum ItemFlagsCustom @@ -194,6 +205,28 @@ enum ItemFlagsCustom ITEM_FLAGS_CU_FOLLOW_LOOT_RULES = 0x0004 // Item will always follow group/master/need before greed looting rules }; +enum CurrencyFlags +{ + CURRENCY_FLAG_TRADEABLE = 0x01, + // ... + CURRENCY_FLAG_HIGH_PRECISION = 0x08, + // ... + CURRENCY_FLAG_COUNT_SEASON_TOTAL = 0x80, +}; + +enum CurrencyCategory +{ + // ... + CURRENCY_CATEGORY_META_CONQUEST = 89, + // ... +}; + +enum ItemVendorType +{ + ITEM_VENDOR_TYPE_ITEM = 1, + ITEM_VENDOR_TYPE_CURRENCY = 2, +}; + enum BAG_FAMILY_MASK { BAG_FAMILY_MASK_NONE = 0x00000000, @@ -211,7 +244,8 @@ enum BAG_FAMILY_MASK BAG_FAMILY_MASK_SOULBOUND_EQUIPMENT = 0x00000800, BAG_FAMILY_MASK_VANITY_PETS = 0x00001000, BAG_FAMILY_MASK_CURRENCY_TOKENS = 0x00002000, - BAG_FAMILY_MASK_QUEST_ITEMS = 0x00004000 + BAG_FAMILY_MASK_QUEST_ITEMS = 0x00004000, + BAG_FAMILY_MASK_FISHING_SUPP = 0x00008000, }; enum SocketColor @@ -219,10 +253,12 @@ enum SocketColor SOCKET_COLOR_META = 1, SOCKET_COLOR_RED = 2, SOCKET_COLOR_YELLOW = 4, - SOCKET_COLOR_BLUE = 8 + SOCKET_COLOR_BLUE = 8, + SOCKET_COLOR_HYDRAULIC = 16, // not used + SOCKET_COLOR_COGWHEEL = 32, }; -#define SOCKET_COLOR_ALL (SOCKET_COLOR_META | SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE) +#define SOCKET_COLOR_ALL (SOCKET_COLOR_META | SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE | SOCKET_COLOR_COGWHEEL) enum InventoryType { @@ -269,14 +305,14 @@ enum ItemClass ITEM_CLASS_REAGENT = 5, ITEM_CLASS_PROJECTILE = 6, ITEM_CLASS_TRADE_GOODS = 7, - ITEM_CLASS_GENERIC = 8, + ITEM_CLASS_GENERIC = 8, // OBSOLETE ITEM_CLASS_RECIPE = 9, - ITEM_CLASS_MONEY = 10, + ITEM_CLASS_MONEY = 10, // OBSOLETE ITEM_CLASS_QUIVER = 11, ITEM_CLASS_QUEST = 12, ITEM_CLASS_KEY = 13, - ITEM_CLASS_PERMANENT = 14, - ITEM_CLASS_MISC = 15, + ITEM_CLASS_PERMANENT = 14, // OBSOLETE + ITEM_CLASS_MISCELLANEOUS = 15, ITEM_CLASS_GLYPH = 16 }; @@ -289,7 +325,7 @@ enum ItemSubclassConsumable ITEM_SUBCLASS_ELIXIR = 2, ITEM_SUBCLASS_FLASK = 3, ITEM_SUBCLASS_SCROLL = 4, - ITEM_SUBCLASS_FOOD = 5, + ITEM_SUBCLASS_FOOD_DRINK = 5, ITEM_SUBCLASS_ITEM_ENHANCEMENT = 6, ITEM_SUBCLASS_BANDAGE = 7, ITEM_SUBCLASS_CONSUMABLE_OTHER = 8 @@ -307,28 +343,29 @@ enum ItemSubclassContainer ITEM_SUBCLASS_GEM_CONTAINER = 5, ITEM_SUBCLASS_MINING_CONTAINER = 6, ITEM_SUBCLASS_LEATHERWORKING_CONTAINER = 7, - ITEM_SUBCLASS_INSCRIPTION_CONTAINER = 8 + ITEM_SUBCLASS_INSCRIPTION_CONTAINER = 8, + ITEM_SUBCLASS_TACKLE_CONTAINER = 9 }; -#define MAX_ITEM_SUBCLASS_CONTAINER 9 +#define MAX_ITEM_SUBCLASS_CONTAINER 10 enum ItemSubclassWeapon { - ITEM_SUBCLASS_WEAPON_AXE = 0, - ITEM_SUBCLASS_WEAPON_AXE2 = 1, + ITEM_SUBCLASS_WEAPON_AXE = 0, // One-Handed Axes + ITEM_SUBCLASS_WEAPON_AXE2 = 1, // Two-Handed Axes ITEM_SUBCLASS_WEAPON_BOW = 2, ITEM_SUBCLASS_WEAPON_GUN = 3, - ITEM_SUBCLASS_WEAPON_MACE = 4, - ITEM_SUBCLASS_WEAPON_MACE2 = 5, + ITEM_SUBCLASS_WEAPON_MACE = 4, // One-Handed Maces + ITEM_SUBCLASS_WEAPON_MACE2 = 5, // Two-Handed Maces ITEM_SUBCLASS_WEAPON_POLEARM = 6, - ITEM_SUBCLASS_WEAPON_SWORD = 7, - ITEM_SUBCLASS_WEAPON_SWORD2 = 8, - ITEM_SUBCLASS_WEAPON_obsolete = 9, + ITEM_SUBCLASS_WEAPON_SWORD = 7, // One-Handed Swords + ITEM_SUBCLASS_WEAPON_SWORD2 = 8, // Two-Handed Swords + ITEM_SUBCLASS_WEAPON_Obsolete = 9, ITEM_SUBCLASS_WEAPON_STAFF = 10, - ITEM_SUBCLASS_WEAPON_EXOTIC = 11, - ITEM_SUBCLASS_WEAPON_EXOTIC2 = 12, - ITEM_SUBCLASS_WEAPON_FIST = 13, - ITEM_SUBCLASS_WEAPON_MISC = 14, + ITEM_SUBCLASS_WEAPON_EXOTIC = 11, // One-Handed Exotics + ITEM_SUBCLASS_WEAPON_EXOTIC2 = 12, // Two-Handed Exotics + ITEM_SUBCLASS_WEAPON_FIST_WEAPON = 13, + ITEM_SUBCLASS_WEAPON_MISCELLANEOUS = 14, ITEM_SUBCLASS_WEAPON_DAGGER = 15, ITEM_SUBCLASS_WEAPON_THROWN = 16, ITEM_SUBCLASS_WEAPON_SPEAR = 17, @@ -353,27 +390,30 @@ enum ItemSubclassGem ITEM_SUBCLASS_GEM_ORANGE = 5, ITEM_SUBCLASS_GEM_META = 6, ITEM_SUBCLASS_GEM_SIMPLE = 7, - ITEM_SUBCLASS_GEM_PRISMATIC = 8 + ITEM_SUBCLASS_GEM_PRISMATIC = 8, + ITEM_SUBCLASS_GEM_HYDRAULIC = 9, + ITEM_SUBCLASS_GEM_COGWHEEL = 10 }; -#define MAX_ITEM_SUBCLASS_GEM 9 +#define MAX_ITEM_SUBCLASS_GEM 11 enum ItemSubclassArmor { - ITEM_SUBCLASS_ARMOR_MISC = 0, + ITEM_SUBCLASS_ARMOR_MISCELLANEOUS = 0, ITEM_SUBCLASS_ARMOR_CLOTH = 1, ITEM_SUBCLASS_ARMOR_LEATHER = 2, ITEM_SUBCLASS_ARMOR_MAIL = 3, ITEM_SUBCLASS_ARMOR_PLATE = 4, - ITEM_SUBCLASS_ARMOR_BUCKLER = 5, + ITEM_SUBCLASS_ARMOR_BUCKLER = 5, // OBSOLETE ITEM_SUBCLASS_ARMOR_SHIELD = 6, ITEM_SUBCLASS_ARMOR_LIBRAM = 7, ITEM_SUBCLASS_ARMOR_IDOL = 8, ITEM_SUBCLASS_ARMOR_TOTEM = 9, - ITEM_SUBCLASS_ARMOR_SIGIL = 10 + ITEM_SUBCLASS_ARMOR_SIGIL = 10, + ITEM_SUBCLASS_ARMOR_RELIC = 11, }; -#define MAX_ITEM_SUBCLASS_ARMOR 11 +#define MAX_ITEM_SUBCLASS_ARMOR 12 enum ItemSubclassReagent { @@ -384,11 +424,11 @@ enum ItemSubclassReagent enum ItemSubclassProjectile { - ITEM_SUBCLASS_WAND = 0, // ABS - ITEM_SUBCLASS_BOLT = 1, // ABS + ITEM_SUBCLASS_WAND = 0, // OBSOLETE + ITEM_SUBCLASS_BOLT = 1, // OBSOLETE ITEM_SUBCLASS_ARROW = 2, ITEM_SUBCLASS_BULLET = 3, - ITEM_SUBCLASS_THROWN = 4 // ABS + ITEM_SUBCLASS_THROWN = 4 // OBSOLETE }; #define MAX_ITEM_SUBCLASS_PROJECTILE 5 @@ -409,15 +449,14 @@ enum ItemSubclassTradeGoods ITEM_SUBCLASS_TRADE_GOODS_OTHER = 11, ITEM_SUBCLASS_ENCHANTING = 12, ITEM_SUBCLASS_MATERIAL = 13, - ITEM_SUBCLASS_ARMOR_ENCHANTMENT = 14, - ITEM_SUBCLASS_WEAPON_ENCHANTMENT = 15 + ITEM_SUBCLASS_ENCHANTMENT = 14, }; -#define MAX_ITEM_SUBCLASS_TRADE_GOODS 16 +#define MAX_ITEM_SUBCLASS_TRADE_GOODS 15 enum ItemSubclassGeneric { - ITEM_SUBCLASS_GENERIC = 0 + ITEM_SUBCLASS_GENERIC = 0 // OBSOLETE }; #define MAX_ITEM_SUBCLASS_GENERIC 1 @@ -434,22 +473,24 @@ enum ItemSubclassRecipe ITEM_SUBCLASS_FIRST_AID_MANUAL = 7, ITEM_SUBCLASS_ENCHANTING_FORMULA = 8, ITEM_SUBCLASS_FISHING_MANUAL = 9, - ITEM_SUBCLASS_JEWELCRAFTING_RECIPE = 10 + ITEM_SUBCLASS_JEWELCRAFTING_RECIPE = 10, + ITEM_SUBCLASS_INSCRIPTION_TECHNIQUE = 11 }; -#define MAX_ITEM_SUBCLASS_RECIPE 11 +#define MAX_ITEM_SUBCLASS_RECIPE 12 enum ItemSubclassMoney { - ITEM_SUBCLASS_MONEY = 0 + ITEM_SUBCLASS_MONEY = 0, // OBSOLETE + ITEM_SUBCLASS_MONEY_UNK_7 = 7, // OBSOLETE, 1 item (41749) }; -#define MAX_ITEM_SUBCLASS_MONEY 1 +#define MAX_ITEM_SUBCLASS_MONEY 8 enum ItemSubclassQuiver { - ITEM_SUBCLASS_QUIVER0 = 0, // ABS - ITEM_SUBCLASS_QUIVER1 = 1, // ABS + ITEM_SUBCLASS_QUIVER0 = 0, // OBSOLETE + ITEM_SUBCLASS_QUIVER1 = 1, // OBSOLETE ITEM_SUBCLASS_QUIVER = 2, ITEM_SUBCLASS_AMMO_POUCH = 3 }; @@ -458,10 +499,12 @@ enum ItemSubclassQuiver enum ItemSubclassQuest { - ITEM_SUBCLASS_QUEST = 0 + ITEM_SUBCLASS_QUEST = 0, + ITEM_SUBCLASS_QUEST_UNK3 = 3, // 1 item (33604) + ITEM_SUBCLASS_QUEST_UNK8 = 8, // 2 items (37445, 49700) }; -#define MAX_ITEM_SUBCLASS_QUEST 1 +#define MAX_ITEM_SUBCLASS_QUEST 9 enum ItemSubclassKey { @@ -485,10 +528,11 @@ enum ItemSubclassJunk ITEM_SUBCLASS_JUNK_PET = 2, ITEM_SUBCLASS_JUNK_HOLIDAY = 3, ITEM_SUBCLASS_JUNK_OTHER = 4, - ITEM_SUBCLASS_JUNK_MOUNT = 5 + ITEM_SUBCLASS_JUNK_MOUNT = 5, + ITEM_SUBCLASS_JUNK_UNK12 = 12, // 1 item (37677) }; -#define MAX_ITEM_SUBCLASS_JUNK 6 +#define MAX_ITEM_SUBCLASS_JUNK 13 enum ItemSubclassGlyph { @@ -544,24 +588,19 @@ inline uint8 ItemSubClassToDurabilityMultiplierId(uint32 ItemClass, uint32 ItemS #pragma pack(push, 1) #endif -struct _Damage -{ - float DamageMin; - float DamageMax; - uint32 DamageType; // id from Resistances.dbc -}; - struct _ItemStat { uint32 ItemStatType; int32 ItemStatValue; + int32 ItemStatUnk1; + int32 ItemStatUnk2; }; + struct _Spell { int32 SpellId; // id from Spell.dbc uint32 SpellTrigger; int32 SpellCharges; - float SpellPPMRate; int32 SpellCooldown; uint32 SpellCategory; // id from SpellCategory.dbc int32 SpellCategoryCooldown; @@ -596,6 +635,8 @@ struct ItemTemplate uint32 Quality; uint32 Flags; uint32 Flags2; + float Unk430_1; + float Unk430_2; uint32 BuyCount; int32 BuyPrice; uint32 SellPrice; @@ -614,24 +655,14 @@ struct ItemTemplate int32 MaxCount; // <= 0: no limit int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot) uint32 ContainerSlots; - uint32 StatsCount; _ItemStat ItemStat[MAX_ITEM_PROTO_STATS]; uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc - uint32 ScalingStatValue; // mask for selecting column in ScalingStatValues.dbc - _Damage Damage[MAX_ITEM_PROTO_DAMAGES]; - uint32 Armor; - uint32 HolyRes; - uint32 FireRes; - uint32 NatureRes; - uint32 FrostRes; - uint32 ShadowRes; - uint32 ArcaneRes; + uint32 DamageType; // id from Resistances.dbc uint32 Delay; - uint32 AmmoType; float RangedModRange; _Spell Spells[MAX_ITEM_PROTO_SPELLS]; uint32 Bonding; - std::string Description; + std::string Description; uint32 PageText; uint32 LanguageID; uint32 PageMaterial; @@ -641,7 +672,6 @@ struct ItemTemplate uint32 Sheath; int32 RandomProperty; // id from ItemRandomProperties.dbc int32 RandomSuffix; // id from ItemRandomSuffix.dbc - uint32 Block; uint32 ItemSet; // id from ItemSet.dbc uint32 MaxDurability; uint32 Area; // id from AreaTable.dbc @@ -651,13 +681,23 @@ struct ItemTemplate _Socket Socket[MAX_ITEM_PROTO_SOCKETS]; uint32 socketBonus; // id from SpellItemEnchantment.dbc uint32 GemProperties; // id from GemProperties.dbc - uint32 RequiredDisenchantSkill; float ArmorDamageModifier; uint32 Duration; uint32 ItemLimitCategory; // id from ItemLimitCategory.dbc uint32 HolidayId; // id from Holidays.dbc + float StatScalingFactor; + uint32 CurrencySubstitutionId; // May be used instead of a currency + uint32 CurrencySubstitutionCount; + + // extra fields, not part of db2 files + float DamageMin; + float DamageMax; + float DPS; + uint32 Armor; + float SpellPPMRate; uint32 ScriptId; uint32 DisenchantID; + uint32 RequiredDisenchantSkill; uint32 FoodType; uint32 MinMoneyLoot; uint32 MaxMoneyLoot; @@ -691,29 +731,6 @@ struct ItemTemplate return (Stackable == 2147483647 || Stackable <= 0) ? uint32(0x7FFFFFFF-1) : uint32(Stackable); } - float getDPS() const - { - if (Delay == 0) - return 0; - float temp = 0; - for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) - temp+=Damage[i].DamageMin + Damage[i].DamageMax; - return temp*500/Delay; - } - - int32 getFeralBonus(int32 extraDPS = 0) const - { - // 0x02A5F3 - is mask for Melee weapon from ItemSubClassMask.dbc - if (Class == ITEM_CLASS_WEAPON && (1<<SubClass)&0x02A5F3) - { - int32 bonus = int32((extraDPS + getDPS())*14.0f) - 767; - if (bonus < 0) - return 0; - return bonus; - } - return 0; - } - float GetItemLevelIncludingQuality() const { float itemLevel = (float)ItemLevel; @@ -738,9 +755,16 @@ struct ItemTemplate } bool IsPotion() const { return Class == ITEM_CLASS_CONSUMABLE && SubClass == ITEM_SUBCLASS_POTION; } - bool IsWeaponVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_WEAPON_ENCHANTMENT; } - bool IsArmorVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_ARMOR_ENCHANTMENT; } + bool IsVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_ENCHANTMENT; } bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_PROTO_FLAG_CONJURED); } + + bool IsRangedWeapon() const + { + return Class == ITEM_CLASS_WEAPON || + SubClass == ITEM_SUBCLASS_WEAPON_BOW || + SubClass == ITEM_SUBCLASS_WEAPON_GUN || + SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW; + } }; // Benchmarked: Faster than std::map (insert/find) @@ -752,15 +776,4 @@ struct ItemLocale StringVector Description; }; -struct ItemSetNameEntry -{ - std::string name; - uint32 InventoryType; -}; - -struct ItemSetNameLocale -{ - StringVector Name; -}; - #endif diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index dfc0c438662..51087e0f966 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -47,6 +47,7 @@ #include "OutdoorPvPMgr.h" #include "MovementPacketBuilder.h" #include "DynamicTree.h" +#include "Unit.h" #include "Group.h" #include "BattlefieldMgr.h" #include "Battleground.h" @@ -64,6 +65,7 @@ uint32 GuidHigh2TypeId(uint32 guid_hi) case HIGHGUID_GAMEOBJECT: return TYPEID_GAMEOBJECT; case HIGHGUID_DYNAMICOBJECT:return TYPEID_DYNAMICOBJECT; case HIGHGUID_CORPSE: return TYPEID_CORPSE; + case HIGHGUID_AREATRIGGER: return TYPEID_AREATRIGGER; case HIGHGUID_MO_TRANSPORT: return TYPEID_GAMEOBJECT; case HIGHGUID_VEHICLE: return TYPEID_UNIT; } @@ -138,8 +140,8 @@ void Object::_Create(uint32 guidlow, uint32 entry, HighGuid guidhigh) uint64 guid = MAKE_NEW_GUID(guidlow, entry, guidhigh); SetUInt64Value(OBJECT_FIELD_GUID, guid); - SetUInt32Value(OBJECT_FIELD_TYPE, m_objectType); - m_PackGUID.wpos(0); + SetUInt16Value(OBJECT_FIELD_TYPE, 0, m_objectType); + m_PackGUID.clear(); m_PackGUID.appendPackGUID(GetGUID()); } @@ -175,18 +177,6 @@ void Object::RemoveFromWorld() ClearUpdateMask(true); } -void Object::BuildMovementUpdateBlock(UpdateData* data, uint32 flags) const -{ - ByteBuffer buf(500); - - buf << uint8(UPDATETYPE_MOVEMENT); - buf.append(GetPackGUID()); - - BuildMovementUpdate(&buf, flags); - - data->AddUpdateBlock(buf); -} - void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const { if (!target) @@ -199,16 +189,36 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c if (target == this) // building packet for yourself flags |= UPDATEFLAG_SELF; - if (flags & UPDATEFLAG_STATIONARY_POSITION) + switch (GetGUIDHigh()) { - // UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses... - if (isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER)) + case HIGHGUID_PLAYER: + case HIGHGUID_PET: + case HIGHGUID_CORPSE: + case HIGHGUID_DYNAMICOBJECT: + case HIGHGUID_AREATRIGGER: updateType = UPDATETYPE_CREATE_OBJECT2; + break; + case HIGHGUID_UNIT: + case HIGHGUID_VEHICLE: + { + if (TempSummon const* summon = ToUnit()->ToTempSummon()) + if (IS_PLAYER_GUID(summon->GetSummonerGUID())) + updateType = UPDATETYPE_CREATE_OBJECT2; - // UPDATETYPE_CREATE_OBJECT2 for pets... - if (target->GetPetGUID() == GetGUID()) - updateType = UPDATETYPE_CREATE_OBJECT2; + break; + } + case HIGHGUID_GAMEOBJECT: + { + if (IS_PLAYER_GUID(ToGameObject()->GetOwnerGUID())) + updateType = UPDATETYPE_CREATE_OBJECT2; + break; + } + default: + break; + } + if (flags & UPDATEFLAG_STATIONARY_POSITION) + { // UPDATETYPE_CREATE_OBJECT2 for some gameobject types... if (isType(TYPEMASK_GAMEOBJECT)) { @@ -224,15 +234,11 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c break; } } - - if (isType(TYPEMASK_UNIT)) - { - if (ToUnit()->GetVictim()) - flags |= UPDATEFLAG_HAS_TARGET; - } } - //TC_LOG_DEBUG("BuildCreateUpdate: update-type: %u, object-type: %u got flags: %X, flags2: %X", updateType, m_objectTypeId, flags, flags2); + if (Unit const* unit = ToUnit()) + if (unit->GetVictim()) + flags |= UPDATEFLAG_HAS_TARGET; ByteBuffer buf(500); buf << uint8(updateType); @@ -247,7 +253,7 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c void Object::SendUpdateToPlayer(Player* player) { // send create update to player - UpdateData upd; + UpdateData upd(player->GetMapId()); WorldPacket packet; BuildCreateUpdateBlockForPlayer(&upd, player); @@ -337,139 +343,315 @@ uint16 Object::GetUInt16Value(uint16 index, uint8 offset) const void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const { - Unit const* unit = NULL; - WorldObject const* object = NULL; + Unit const* self = NULL; + ObjectGuid guid = GetGUID(); + uint32 movementFlags = 0; + uint16 movementFlagsExtra = 0; + + bool hasTransportTime2 = false; + bool hasTransportTime3 = false; + bool hasFallDirection = false; + bool hasFallData = false; + bool hasPitch = false; + bool hasSpline = false; + bool hasSplineElevation = false; + + uint32 unkLoopCounter = 0; + // Bit content + data->WriteBit(0); + data->WriteBit(0); + data->WriteBit(flags & UPDATEFLAG_ROTATION); + data->WriteBit(flags & UPDATEFLAG_ANIMKITS); + data->WriteBit(flags & UPDATEFLAG_HAS_TARGET); + data->WriteBit(flags & UPDATEFLAG_SELF); + data->WriteBit(flags & UPDATEFLAG_VEHICLE); + data->WriteBit(flags & UPDATEFLAG_LIVING); + data->WriteBits(unkLoopCounter, 24); + data->WriteBit(0); + data->WriteBit(flags & UPDATEFLAG_GO_TRANSPORT_POSITION); + data->WriteBit(flags & UPDATEFLAG_STATIONARY_POSITION); + data->WriteBit(flags & UPDATEFLAG_UNK5); + data->WriteBit(0); + data->WriteBit(flags & UPDATEFLAG_TRANSPORT); - if (isType(TYPEMASK_UNIT)) - unit = ToUnit(); - else - object = (WorldObject const*)this; - - *data << uint16(flags); // update flags - - // 0x20 if (flags & UPDATEFLAG_LIVING) { - ASSERT(unit); - unit->BuildMovementPacket(data); + self = ToUnit(); + movementFlags = self->m_movementInfo.GetMovementFlags(); + movementFlagsExtra = self->m_movementInfo.GetExtraMovementFlags(); + hasSpline = self->IsSplineEnabled(); + + hasTransportTime2 = self->m_movementInfo.transport.guid != 0 && self->m_movementInfo.transport.time2 != 0; + hasTransportTime3 = false; + hasPitch = self->HasUnitMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || self->HasExtraUnitMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING); + hasFallDirection = self->HasUnitMovementFlag(MOVEMENTFLAG_FALLING); + hasFallData = hasFallDirection || self->m_movementInfo.jump.fallTime != 0; + hasSplineElevation = self->HasUnitMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION); - *data << unit->GetSpeed(MOVE_WALK) - << unit->GetSpeed(MOVE_RUN) - << unit->GetSpeed(MOVE_RUN_BACK) - << unit->GetSpeed(MOVE_SWIM) - << unit->GetSpeed(MOVE_SWIM_BACK) - << unit->GetSpeed(MOVE_FLIGHT) - << unit->GetSpeed(MOVE_FLIGHT_BACK) - << unit->GetSpeed(MOVE_TURN_RATE) - << unit->GetSpeed(MOVE_PITCH_RATE); + if (GetTypeId() == TYPEID_UNIT) + movementFlags &= MOVEMENTFLAG_MASK_CREATURE_ALLOWED; + + data->WriteBit(!movementFlags); + data->WriteBit(G3D::fuzzyEq(self->GetOrientation(), 0.0f)); // Has Orientation + data->WriteBit(guid[7]); + data->WriteBit(guid[3]); + data->WriteBit(guid[2]); + if (movementFlags) + data->WriteBits(movementFlags, 30); + + data->WriteBit(hasSpline && GetTypeId() == TYPEID_PLAYER); // Has spline (from MovementInfo) + data->WriteBit(!hasPitch); // Has pitch + data->WriteBit(hasSpline); // Has spline data (independent) + data->WriteBit(hasFallData); // Has fall data + data->WriteBit(!hasSplineElevation); // Has spline elevation + data->WriteBit(guid[5]); + data->WriteBit(self->m_movementInfo.transport.guid); // Has transport data + data->WriteBit(0); // Is missing time + + if (self->m_movementInfo.transport.guid) + { + ObjectGuid transGuid = self->m_movementInfo.transport.guid; + + data->WriteBit(transGuid[1]); + data->WriteBit(hasTransportTime2); // Has transport time 2 + data->WriteBit(transGuid[4]); + data->WriteBit(transGuid[0]); + data->WriteBit(transGuid[6]); + data->WriteBit(hasTransportTime3); // Has transport time 3 + data->WriteBit(transGuid[7]); + data->WriteBit(transGuid[5]); + data->WriteBit(transGuid[3]); + data->WriteBit(transGuid[2]); + } + + data->WriteBit(guid[4]); - // 0x08000000 - if (unit->m_movementInfo.GetMovementFlags() & MOVEMENTFLAG_SPLINE_ENABLED) - Movement::PacketBuilder::WriteCreate(*unit->movespline, *data); + if (hasSpline) + Movement::PacketBuilder::WriteCreateBits(*self->movespline, *data); + + data->WriteBit(guid[6]); + if (hasFallData) + data->WriteBit(hasFallDirection); + + data->WriteBit(guid[0]); + data->WriteBit(guid[1]); + data->WriteBit(0); + data->WriteBit(!movementFlagsExtra); + if (movementFlagsExtra) + data->WriteBits(movementFlagsExtra, 12); } - else + + if (flags & UPDATEFLAG_GO_TRANSPORT_POSITION) { - if (flags & UPDATEFLAG_POSITION) - { - ASSERT(object); - Transport* transport = object->GetTransport(); + WorldObject const* self = static_cast<WorldObject const*>(this); + ObjectGuid transGuid = self->m_movementInfo.transport.guid; + data->WriteBit(transGuid[5]); + data->WriteBit(0); // Has GO transport time 3 + data->WriteBit(transGuid[0]); + data->WriteBit(transGuid[3]); + data->WriteBit(transGuid[6]); + data->WriteBit(transGuid[1]); + data->WriteBit(transGuid[4]); + data->WriteBit(transGuid[2]); + data->WriteBit(0); // Has GO transport time 2 + data->WriteBit(transGuid[7]); + } - if (transport) - data->append(transport->GetPackGUID()); - else - *data << uint8(0); + if (flags & UPDATEFLAG_HAS_TARGET) + { + ObjectGuid victimGuid = self->GetVictim()->GetGUID(); // checked in BuildCreateUpdateBlockForPlayer + data->WriteBit(victimGuid[2]); + data->WriteBit(victimGuid[7]); + data->WriteBit(victimGuid[0]); + data->WriteBit(victimGuid[4]); + data->WriteBit(victimGuid[5]); + data->WriteBit(victimGuid[6]); + data->WriteBit(victimGuid[1]); + data->WriteBit(victimGuid[3]); + } - *data << object->GetPositionX(); - *data << object->GetPositionY(); - if (isType(TYPEMASK_UNIT)) - *data << unit->GetPositionZMinusOffset(); - else - *data << object->GetPositionZ(); + if (flags & UPDATEFLAG_ANIMKITS) + { + data->WriteBit(1); // Missing AnimKit1 + data->WriteBit(1); // Missing AnimKit2 + data->WriteBit(1); // Missing AnimKit3 + } - if (transport) - { - *data << object->GetTransOffsetX(); - *data << object->GetTransOffsetY(); - *data << object->GetTransOffsetZ(); - } - else - { - *data << object->GetPositionX(); - *data << object->GetPositionY(); - if (isType(TYPEMASK_UNIT)) - *data << unit->GetPositionZMinusOffset(); - else - *data << object->GetPositionZ(); - } + data->FlushBits(); - *data << object->GetOrientation(); + // Data + for (uint32 i = 0; i < unkLoopCounter; ++i) + *data << uint32(0); - if (GetTypeId() == TYPEID_CORPSE) - *data << float(object->GetOrientation()); - else - *data << float(0); - } - else + if (flags & UPDATEFLAG_LIVING) + { + data->WriteByteSeq(guid[4]); + *data << self->GetSpeed(MOVE_RUN_BACK); + + if (hasFallData) { - // 0x40 - if (flags & UPDATEFLAG_STATIONARY_POSITION) + if (hasFallDirection) { - ASSERT(object); - *data << object->GetStationaryX(); - *data << object->GetStationaryY(); - *data << object->GetStationaryZ(); - *data << object->GetStationaryO(); + *data << float(self->m_movementInfo.jump.xyspeed); + *data << float(self->m_movementInfo.jump.sinAngle); + *data << float(self->m_movementInfo.jump.cosAngle); } + + *data << uint32(self->m_movementInfo.jump.fallTime); + *data << float(self->m_movementInfo.jump.zspeed); + } + + *data << self->GetSpeed(MOVE_SWIM_BACK); + if (hasSplineElevation) + *data << float(self->m_movementInfo.splineElevation); + + if (hasSpline) + Movement::PacketBuilder::WriteCreateData(*self->movespline, *data); + + *data << float(self->GetPositionZMinusOffset()); + data->WriteByteSeq(guid[5]); + + if (self->m_movementInfo.transport.guid) + { + ObjectGuid transGuid = self->m_movementInfo.transport.guid; + + data->WriteByteSeq(transGuid[5]); + data->WriteByteSeq(transGuid[7]); + *data << uint32(self->GetTransTime()); + *data << float(self->GetTransOffsetO()); + if (hasTransportTime2) + *data << uint32(self->m_movementInfo.transport.time2); + + *data << float(self->GetTransOffsetY()); + *data << float(self->GetTransOffsetX()); + data->WriteByteSeq(transGuid[3]); + *data << float(self->GetTransOffsetZ()); + data->WriteByteSeq(transGuid[0]); + if (hasTransportTime3) + *data << uint32(self->m_movementInfo.transport.time3); + + *data << int8(self->GetTransSeat()); + data->WriteByteSeq(transGuid[1]); + data->WriteByteSeq(transGuid[6]); + data->WriteByteSeq(transGuid[2]); + data->WriteByteSeq(transGuid[4]); } + + *data << float(self->GetPositionX()); + *data << self->GetSpeed(MOVE_PITCH_RATE); + data->WriteByteSeq(guid[3]); + data->WriteByteSeq(guid[0]); + *data << self->GetSpeed(MOVE_SWIM); + *data << float(self->GetPositionY()); + data->WriteByteSeq(guid[7]); + data->WriteByteSeq(guid[1]); + data->WriteByteSeq(guid[2]); + *data << self->GetSpeed(MOVE_WALK); + + //if (true) // Has time, controlled by bit just after HasTransport + *data << uint32(getMSTime()); + + *data << self->GetSpeed(MOVE_TURN_RATE); + data->WriteByteSeq(guid[6]); + *data << self->GetSpeed(MOVE_FLIGHT); + if (!G3D::fuzzyEq(self->GetOrientation(), 0.0f)) + *data << float(self->GetOrientation()); + + *data << self->GetSpeed(MOVE_RUN); + if (hasPitch) + *data << float(self->m_movementInfo.pitch); + + *data << self->GetSpeed(MOVE_FLIGHT_BACK); } - // 0x8 - if (flags & UPDATEFLAG_UNKNOWN) + if (flags & UPDATEFLAG_VEHICLE) { - *data << uint32(0); + *data << float(self->GetOrientation()); + *data << uint32(self->GetVehicleKit()->GetVehicleInfo()->m_ID); } - // 0x10 - if (flags & UPDATEFLAG_LOWGUID) + if (flags & UPDATEFLAG_GO_TRANSPORT_POSITION) { - switch (GetTypeId()) - { - case TYPEID_OBJECT: - case TYPEID_ITEM: - case TYPEID_CONTAINER: - case TYPEID_GAMEOBJECT: - case TYPEID_DYNAMICOBJECT: - case TYPEID_CORPSE: - *data << uint32(GetGUIDLow()); // GetGUIDLow() - break; - //! Unit, Player and default here are sending wrong values. - /// @todo Research the proper formula - case TYPEID_UNIT: - *data << uint32(0x0000000B); // unk - break; - case TYPEID_PLAYER: - if (flags & UPDATEFLAG_SELF) - *data << uint32(0x0000002F); // unk - else - *data << uint32(0x00000008); // unk - break; - default: - *data << uint32(0x00000000); // unk - break; - } + WorldObject const* self = static_cast<WorldObject const*>(this); + ObjectGuid transGuid = self->m_movementInfo.transport.guid; + + data->WriteBit(transGuid[0]); + data->WriteBit(transGuid[5]); + if (hasTransportTime3) + *data << uint32(self->m_movementInfo.transport.time3); + + data->WriteBit(transGuid[3]); + *data << float(self->GetTransOffsetX()); + data->WriteBit(transGuid[4]); + data->WriteBit(transGuid[6]); + data->WriteBit(transGuid[1]); + *data << uint32(self->GetTransTime()); + *data << float(self->GetTransOffsetY()); + data->WriteBit(transGuid[2]); + data->WriteBit(transGuid[7]); + *data << float(self->GetTransOffsetZ()); + *data << int8(self->GetTransSeat()); + *data << float(self->GetTransOffsetO()); + if (hasTransportTime2) + *data << uint32(self->m_movementInfo.transport.time2); } - // 0x4 - if (flags & UPDATEFLAG_HAS_TARGET) + if (flags & UPDATEFLAG_ROTATION) + *data << uint64(ToGameObject()->GetRotation()); + + if (flags & UPDATEFLAG_UNK5) + { + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << uint8(0); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + *data << float(0.0f); + } + + if (flags & UPDATEFLAG_STATIONARY_POSITION) { - ASSERT(unit); - if (Unit* victim = unit->GetVictim()) - data->append(victim->GetPackGUID()); - else - *data << uint8(0); + WorldObject const* self = static_cast<WorldObject const*>(this); + *data << float(self->GetStationaryO()); + *data << float(self->GetStationaryX()); + *data << float(self->GetStationaryY()); + *data << float(self->GetStationaryZ()); } - // 0x2 + if (flags & UPDATEFLAG_HAS_TARGET) + { + ObjectGuid victimGuid = self->GetVictim()->GetGUID(); // checked in BuildCreateUpdateBlockForPlayer + data->WriteByteSeq(victimGuid[4]); + data->WriteByteSeq(victimGuid[0]); + data->WriteByteSeq(victimGuid[3]); + data->WriteByteSeq(victimGuid[5]); + data->WriteByteSeq(victimGuid[7]); + data->WriteByteSeq(victimGuid[6]); + data->WriteByteSeq(victimGuid[2]); + data->WriteByteSeq(victimGuid[1]); + } + + //if (flags & UPDATEFLAG_ANIMKITS) + //{ + // if (hasAnimKit1) + // *data << uint16(animKit1); + // if (hasAnimKit2) + // *data << uint16(animKit2); + // if (hasAnimKit3) + // *data << uint16(animKit3); + //} + if (flags & UPDATEFLAG_TRANSPORT) { GameObject const* go = ToGameObject(); @@ -483,24 +665,6 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const else *data << uint32(getMSTime()); } - - // 0x80 - if (flags & UPDATEFLAG_VEHICLE) - { - /// @todo Allow players to aquire this updateflag. - ASSERT(unit); - ASSERT(unit->GetVehicleKit()); - ASSERT(unit->GetVehicleKit()->GetVehicleInfo()); - *data << uint32(unit->GetVehicleKit()->GetVehicleInfo()->m_ID); - if (unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) - *data << float(unit->GetTransOffsetO()); - else - *data << float(unit->GetOrientation()); - } - - // 0x200 - if (flags & UPDATEFLAG_ROTATION) - *data << int64(ToGameObject()->GetRotation()); } void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const @@ -548,7 +712,7 @@ void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) cons if (iter == data_map.end()) { - std::pair<UpdateDataMapType::iterator, bool> p = data_map.emplace(player, UpdateData()); + std::pair<UpdateDataMapType::iterator, bool> p = data_map.emplace(player, UpdateData(player->GetMapId())); ASSERT(p.second); iter = p.first; } @@ -602,6 +766,9 @@ uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const if (ToCorpse()->GetOwnerGUID() == target->GetGUID()) visibleFlag |= UF_FLAG_OWNER; break; + case TYPEID_AREATRIGGER: + flags = AreaTriggerUpdateFieldFlags; + break; case TYPEID_OBJECT: break; } @@ -1072,11 +1239,11 @@ void MovementInfo::OutDebug() { TC_LOG_INFO("misc", "MOVEMENT INFO"); TC_LOG_INFO("misc", "guid " UI64FMTD, guid); - TC_LOG_INFO("misc", "flags %u", flags); - TC_LOG_INFO("misc", "flags2 %u", flags2); - TC_LOG_INFO("misc", "time %u current time " UI64FMTD "", flags2, uint64(::time(NULL))); + TC_LOG_INFO("misc", "flags %s (%u)", Movement::MovementFlags_ToString(flags).c_str(), flags); + TC_LOG_INFO("misc", "flags2 %s (%u)", Movement::MovementFlagsExtra_ToString(flags2).c_str(), flags2); + TC_LOG_INFO("misc", "time %u current time %u", time, getMSTime()); TC_LOG_INFO("misc", "position: `%s`", pos.ToString().c_str()); - if (flags & MOVEMENTFLAG_ONTRANSPORT) + if (transport.guid) { TC_LOG_INFO("misc", "TRANSPORT:"); TC_LOG_INFO("misc", "guid: " UI64FMTD, transport.guid); @@ -1085,14 +1252,19 @@ void MovementInfo::OutDebug() TC_LOG_INFO("misc", "time: %u", transport.time); if (flags2 & MOVEMENTFLAG2_INTERPOLATED_MOVEMENT) TC_LOG_INFO("misc", "time2: %u", transport.time2); + if (transport.time3) + TC_LOG_INFO("misc", "time3: %u", transport.time3); } if ((flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (flags2 & MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING)) TC_LOG_INFO("misc", "pitch: %f", pitch); - TC_LOG_INFO("misc", "fallTime: %u", fallTime); - if (flags & MOVEMENTFLAG_FALLING) - TC_LOG_INFO("misc", "j_zspeed: %f j_sinAngle: %f j_cosAngle: %f j_xyspeed: %f", jump.zspeed, jump.sinAngle, jump.cosAngle, jump.xyspeed); + if (flags & MOVEMENTFLAG_FALLING || jump.fallTime) + { + TC_LOG_INFO("misc", "fallTime: %u j_zspeed: %f", jump.fallTime, jump.zspeed); + if (flags & MOVEMENTFLAG_FALLING) + TC_LOG_INFO("misc", "j_sinAngle: %f j_cosAngle: %f j_xyspeed: %f", jump.sinAngle, jump.cosAngle, jump.xyspeed); + } if (flags & MOVEMENTFLAG_SPLINE_ELEVATION) TC_LOG_INFO("misc", "splineElevation: %f", splineElevation); @@ -1324,7 +1496,7 @@ bool WorldObject::IsWithinDist(WorldObject const* obj, float dist2compare, bool bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D /*= true*/) const { - return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D); + return obj && IsInMap(obj) && IsInPhase(obj) && _IsWithinDist(obj, dist2compare, is3D); } bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const @@ -1763,7 +1935,7 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo bool WorldObject::CanNeverSee(WorldObject const* obj) const { - return GetMap() != obj->GetMap() || !InSamePhase(obj); + return GetMap() != obj->GetMap() || !IsInPhase(obj); } bool WorldObject::CanDetect(WorldObject const* obj, bool ignoreStealth) const @@ -1795,13 +1967,6 @@ bool WorldObject::CanDetectInvisibilityOf(WorldObject const* obj) const if (mask != obj->m_invisibility.GetFlags()) return false; - // It isn't possible in invisibility to detect something that can't detect the invisible object - // (it's at least true for spell: 66) - // It seems like that only Units are affected by this check (couldn't see arena doors with preparation invisibility) - if (obj->ToUnit()) - if ((m_invisibility.GetFlags() & obj->m_invisibilityDetect.GetFlags()) != m_invisibility.GetFlags()) - return false; - for (uint32 i = 0; i < TOTAL_INVISIBILITY_TYPES; ++i) { if (!(mask & (1 << i))) @@ -1881,7 +2046,8 @@ bool WorldObject::CanDetectStealthOf(WorldObject const* obj) const void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf) { WorldPacket data(SMSG_PLAY_SOUND, 4); - data << Sound; + data << uint32(Sound); + data << uint64(GetGUID()); if (OnlySelf && GetTypeId() == TYPEID_PLAYER) this->ToPlayer()->GetSession()->SendPacket(&data); else @@ -2041,13 +2207,6 @@ void WorldObject::MonsterWhisper(int32 textId, Player const* target, bool IsBoss target->GetSession()->SendPacket(&data); } -void Unit::BuildHeartBeatMsg(WorldPacket* data) const -{ - data->Initialize(MSG_MOVE_HEARTBEAT, 32); - data->append(GetPackGUID()); - BuildMovementPacket(data); -} - void WorldObject::SendMessageToSet(WorldPacket* data, bool self) { if (IsInWorld()) @@ -2173,9 +2332,9 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert } } - uint32 phase = PHASEMASK_NORMAL; + std::set<uint32> phases; if (summoner) - phase = summoner->GetPhaseMask(); + phases = summoner->GetPhases(); TempSummon* summon = NULL; switch (mask) @@ -2197,12 +2356,16 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert break; } - if (!summon->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), this, phase, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), nullptr, vehId)) + if (!summon->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), this, 0, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), nullptr, vehId)) { delete summon; return NULL; } + // Set the summon to the summoner's phase + for (auto phaseId : phases) + summon->SetInPhase(phaseId, false, true); + summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); summon->SetHomePosition(pos); @@ -2297,6 +2460,9 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float return NULL; } + for (auto phase : GetPhases()) + go->SetInPhase(phase, false, true); + go->SetRespawnTime(respawnTime); if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this ToUnit()->AddGameObject(go); @@ -2699,9 +2865,36 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) UpdateObjectVisibility(); } +void WorldObject::SetInPhase(uint32 id, bool update, bool apply) +{ + if (apply) + _phases.insert(id); + else + _phases.erase(id); + + if (update && IsInWorld()) + UpdateObjectVisibility(); +} + +bool WorldObject::IsInPhase(WorldObject const* obj) const +{ + // PhaseId 169 is the default fallback phase + if (_phases.empty() && obj->GetPhases().empty()) + return true; + + if (_phases.empty() && obj->IsInPhase(169)) + return true; + + if (obj->GetPhases().empty() && IsInPhase(169)) + return true; + + return Trinity::Containers::Intersects(_phases.begin(), _phases.end(), obj->GetPhases().begin(), obj->GetPhases().end()); +} + bool WorldObject::InSamePhase(WorldObject const* obj) const { - return InSamePhase(obj->GetPhaseMask()); + return IsInPhase(obj); + // return InSamePhase(obj->GetPhaseMask()); } void WorldObject::PlayDistanceSound(uint32 sound_id, Player* target /*= NULL*/) @@ -2719,6 +2912,7 @@ void WorldObject::PlayDirectSound(uint32 sound_id, Player* target /*= NULL*/) { WorldPacket data(SMSG_PLAY_SOUND, 4); data << uint32(sound_id); + data << uint64(GetGUID()); if (target) target->SendDirectMessage(&data); else diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index b82ca1cb0b2..87f94008455 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -56,6 +56,7 @@ enum TypeMask TYPEMASK_GAMEOBJECT = 0x0020, TYPEMASK_DYNAMICOBJECT = 0x0040, TYPEMASK_CORPSE = 0x0080, + TYPEMASK_AREATRIGGER = 0x0100, TYPEMASK_SEER = TYPEMASK_PLAYER | TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT }; @@ -68,10 +69,11 @@ enum TypeID TYPEID_PLAYER = 4, TYPEID_GAMEOBJECT = 5, TYPEID_DYNAMICOBJECT = 6, - TYPEID_CORPSE = 7 + TYPEID_CORPSE = 7, + TYPEID_AREATRIGGER = 8 }; -#define NUM_CLIENT_OBJECT_TYPES 8 +#define NUM_CLIENT_OBJECT_TYPES 9 uint32 GuidHigh2TypeId(uint32 guid_hi); @@ -118,6 +120,62 @@ class ZoneScript; typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType; +//! Structure to ease conversions from single 64 bit integer guid into individual bytes, for packet sending purposes +//! Nuke this out when porting ObjectGuid from MaNGOS, but preserve the per-byte storage +struct ObjectGuid +{ + public: + ObjectGuid() { _data.u64 = UI64LIT(0); } + ObjectGuid(uint64 guid) { _data.u64 = guid; } + ObjectGuid(ObjectGuid const& other) { _data.u64 = other._data.u64; } + + uint8& operator[](uint32 index) + { + ASSERT(index < sizeof(uint64)); + +#if TRINITY_ENDIAN == TRINITY_LITTLEENDIAN + return _data.byte[index]; +#else + return _data.byte[7 - index]; +#endif + } + + uint8 const& operator[](uint32 index) const + { + ASSERT(index < sizeof(uint64)); + +#if TRINITY_ENDIAN == TRINITY_LITTLEENDIAN + return _data.byte[index]; +#else + return _data.byte[7 - index]; +#endif + } + + operator uint64() + { + return _data.u64; + } + + ObjectGuid& operator=(uint64 guid) + { + _data.u64 = guid; + return *this; + } + + ObjectGuid& operator=(ObjectGuid const& other) + { + _data.u64 = other._data.u64; + return *this; + } + + private: + union + { + uint64 u64; + uint8 byte[8]; + } _data; +}; + class Object { public: @@ -147,7 +205,6 @@ class Object void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target) const; void BuildOutOfRangeUpdateBlock(UpdateData* data) const; - void BuildMovementUpdateBlock(UpdateData* data, uint32 flags = 0) const; virtual void DestroyForPlayer(Player* target, bool onDeath = false) const; @@ -229,6 +286,9 @@ class Object DynamicObject* ToDynObject() { if (GetTypeId() == TYPEID_DYNAMICOBJECT) return reinterpret_cast<DynamicObject*>(this); else return NULL; } DynamicObject const* ToDynObject() const { if (GetTypeId() == TYPEID_DYNAMICOBJECT) return reinterpret_cast<DynamicObject const*>(this); else return NULL; } + AreaTrigger* ToAreaTrigger() { if (GetTypeId() == TYPEID_AREATRIGGER) return reinterpret_cast<AreaTrigger*>(this); else return NULL; } + AreaTrigger const* ToAreaTrigger() const { if (GetTypeId() == TYPEID_AREATRIGGER) return reinterpret_cast<AreaTrigger const*>(this); else return NULL; } + protected: Object(); @@ -426,6 +486,7 @@ struct MovementInfo seat = -1; time = 0; time2 = 0; + time3 = 0; } uint64 guid; @@ -433,22 +494,23 @@ struct MovementInfo int8 seat; uint32 time; uint32 time2; + uint32 time3; } transport; // swimming/flying float pitch; - // falling - uint32 fallTime; - - // jumping + // jumping struct JumpInfo { void Reset() { + fallTime = 0; zspeed = sinAngle = cosAngle = xyspeed = 0.0f; } + uint32 fallTime; + float zspeed, sinAngle, cosAngle, xyspeed; } jump; @@ -457,7 +519,7 @@ struct MovementInfo float splineElevation; MovementInfo() : - guid(0), flags(0), flags2(0), time(0), pitch(0.0f), fallTime(0), splineElevation(0.0f) + guid(0), flags(0), flags2(0), time(0), pitch(0.0f), splineElevation(0.0f) { pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); transport.Reset(); @@ -471,10 +533,23 @@ struct MovementInfo bool HasMovementFlag(uint32 flag) const { return (flags & flag) != 0; } uint16 GetExtraMovementFlags() const { return flags2; } + void SetExtraMovementFlags(uint16 flag) { flags2 = flag; } void AddExtraMovementFlag(uint16 flag) { flags2 |= flag; } + void RemoveExtraMovementFlag(uint16 flag) { flags2 &= ~flag; } bool HasExtraMovementFlag(uint16 flag) const { return (flags2 & flag) != 0; } - void SetFallTime(uint32 time) { fallTime = time; } + uint32 GetFallTime() const { return jump.fallTime; } + void SetFallTime(uint32 time) { jump.fallTime = time; } + + void ResetTransport() + { + transport.Reset(); + } + + void ResetJump() + { + jump.Reset(); + } void OutDebug(); }; @@ -602,9 +677,13 @@ class WorldObject : public Object, public WorldLocation uint32 GetInstanceId() const { return m_InstanceId; } virtual void SetPhaseMask(uint32 newPhaseMask, bool update); + virtual void SetInPhase(uint32 id, bool update, bool apply); uint32 GetPhaseMask() const { return m_phaseMask; } bool InSamePhase(WorldObject const* obj) const; bool InSamePhase(uint32 phasemask) const { return (GetPhaseMask() & phasemask) != 0; } + bool IsInPhase(uint32 phase) const { return _phases.find(phase) != _phases.end(); } + bool IsInPhase(WorldObject const* obj) const; + std::set<uint32> const& GetPhases() const { return _phases; } uint32 GetZoneId() const; uint32 GetAreaId() const; @@ -787,6 +866,7 @@ class WorldObject : public Object, public WorldLocation //uint32 m_mapId; // object at map with map_id uint32 m_InstanceId; // in map copy with instance id uint32 m_phaseMask; // in area phase state + std::set<uint32> _phases; uint16 m_notifyflags; uint16 m_executed_notifies; diff --git a/src/server/game/Entities/Object/ObjectDefines.h b/src/server/game/Entities/Object/ObjectDefines.h index 236f77caf5a..03a4f80bf60 100644 --- a/src/server/game/Entities/Object/ObjectDefines.h +++ b/src/server/game/Entities/Object/ObjectDefines.h @@ -23,18 +23,21 @@ enum HighGuid { - HIGHGUID_ITEM = 0x4000, // blizz 4000 - HIGHGUID_CONTAINER = 0x4000, // blizz 4000 - HIGHGUID_PLAYER = 0x0000, // blizz 0000 - HIGHGUID_GAMEOBJECT = 0xF110, // blizz F110 - HIGHGUID_TRANSPORT = 0xF120, // blizz F120 (for GAMEOBJECT_TYPE_TRANSPORT) - HIGHGUID_UNIT = 0xF130, // blizz F130 - HIGHGUID_PET = 0xF140, // blizz F140 - HIGHGUID_VEHICLE = 0xF150, // blizz F550 - HIGHGUID_DYNAMICOBJECT = 0xF100, // blizz F100 + HIGHGUID_ITEM = 0x400, // blizz 4000 + HIGHGUID_CONTAINER = 0x400, // blizz 4000 + HIGHGUID_PLAYER = 0x000, // blizz 0000 + HIGHGUID_GAMEOBJECT = 0xF11, // blizz F110 + HIGHGUID_TRANSPORT = 0xF12, // blizz F120 (for GAMEOBJECT_TYPE_TRANSPORT) + HIGHGUID_UNIT = 0xF13, // blizz F130 + HIGHGUID_PET = 0xF14, // blizz F140 + HIGHGUID_VEHICLE = 0xF15, // blizz F550 + HIGHGUID_DYNAMICOBJECT = 0xF10, // blizz F100 HIGHGUID_CORPSE = 0xF101, // blizz F100 - HIGHGUID_MO_TRANSPORT = 0x1FC0, // blizz 1FC0 (for GAMEOBJECT_TYPE_MO_TRANSPORT) - HIGHGUID_GROUP = 0x1F50 + HIGHGUID_AREATRIGGER = 0xF102, // blizz F100 + HIGHGUID_BATTLEGROUND = 0x1F1, // new 4.x + HIGHGUID_MO_TRANSPORT = 0x1FC, // blizz 1FC0 (for GAMEOBJECT_TYPE_MO_TRANSPORT) + HIGHGUID_GROUP = 0x1F5, + HIGHGUID_GUILD = 0x1FF // new 4.x }; // used for creating values for respawn for example @@ -53,6 +56,7 @@ inline bool IS_VEHICLE_GUID(uint64 guid); inline bool IS_CRE_OR_VEH_GUID(uint64 guid); inline bool IS_CRE_OR_VEH_OR_PET_GUID(uint64 guid); inline bool IS_PLAYER_GUID(uint64 guid); +inline bool IS_GUILD_GUID(uint64 guid); inline bool IS_UNIT_GUID(uint64 guid); inline bool IS_ITEM_GUID(uint64 guid); inline bool IS_GAMEOBJECT_GUID(uint64 guid); @@ -61,6 +65,7 @@ inline bool IS_CORPSE_GUID(uint64 guid); inline bool IS_TRANSPORT_GUID(uint64 guid); inline bool IS_MO_TRANSPORT_GUID(uint64 guid); inline bool IS_GROUP_GUID(uint64 guid); +inline bool IS_AREATRIGGER_GUID(uint64 guid); // l - OBJECT_FIELD_GUID // e - OBJECT_FIELD_ENTRY for GO (except GAMEOBJECT_TYPE_MO_TRANSPORT) and creatures or UNIT_FIELD_PETNUMBER for pets @@ -145,6 +150,11 @@ bool IS_PLAYER_GUID(uint64 guid) return guid != 0 && GUID_HIPART(guid) == HIGHGUID_PLAYER; } +bool IS_GUILD_GUID(uint64 guid) +{ + return GUID_HIPART(guid) == HIGHGUID_GUILD; +} + bool IS_UNIT_GUID(uint64 guid) { return IS_CRE_OR_VEH_OR_PET_GUID(guid) || IS_PLAYER_GUID(guid); @@ -185,28 +195,33 @@ bool IS_GROUP_GUID(uint64 guid) return GUID_HIPART(guid) == HIGHGUID_GROUP; } +bool IS_AREATRIGGER_GUID(uint64 guid) +{ + return GUID_HIPART(guid) == HIGHGUID_AREATRIGGER; +} + uint64 MAKE_NEW_GUID(uint32 l, uint32 e, uint32 h) { - return uint64(uint64(l) | (uint64(e) << 24) | (uint64(h) << 48)); + return uint64(uint64(l) | (uint64(e) << 32) | (uint64(h) << ((h == HIGHGUID_CORPSE || h == HIGHGUID_AREATRIGGER) ? 48 : 52))); } uint32 GUID_HIPART(uint64 guid) { - return (uint32)((uint64(guid) >> 48) & 0x0000FFFF); + uint32 t = ((uint64(guid) >> 48) & 0x0000FFFF); + return (t == HIGHGUID_CORPSE || t == HIGHGUID_AREATRIGGER) ? t : ((t >> 4) & 0x00000FFF); } uint32 GUID_ENPART(uint64 x) { return IsGuidHaveEnPart(x) - ? (uint32)((x >> 24) & UI64LIT(0x0000000000FFFFFF)) + ? ((uint32)((x >> 32) & UI64LIT(0x00000000000FFFFF))) : 0; } uint32 GUID_LOPART(uint64 x) { - return IsGuidHaveEnPart(x) - ? (uint32)(x & UI64LIT(0x0000000000FFFFFF)) - : (uint32)(x & UI64LIT(0x00000000FFFFFFFF)); + // _GUID_LOPART_3 and _GUID_LOPART_2 were both equal to PAIR64_LOPART + return PAIR64_LOPART(x); } bool IsGuidHaveEnPart(uint64 guid) @@ -218,6 +233,7 @@ bool IsGuidHaveEnPart(uint64 guid) case HIGHGUID_DYNAMICOBJECT: case HIGHGUID_CORPSE: case HIGHGUID_GROUP: + case HIGHGUID_GUILD: return false; case HIGHGUID_GAMEOBJECT: case HIGHGUID_TRANSPORT: @@ -225,6 +241,7 @@ bool IsGuidHaveEnPart(uint64 guid) case HIGHGUID_PET: case HIGHGUID_VEHICLE: case HIGHGUID_MO_TRANSPORT: + case HIGHGUID_AREATRIGGER: default: return true; } @@ -245,6 +262,8 @@ char const* GetLogNameForGuid(uint64 guid) case HIGHGUID_CORPSE: return "corpse"; case HIGHGUID_MO_TRANSPORT: return "mo_transport"; case HIGHGUID_GROUP: return "group"; + case HIGHGUID_GUILD: return "guild"; + case HIGHGUID_AREATRIGGER: return "areatrigger"; default: return "<unknown>"; } diff --git a/src/server/game/Entities/Object/Updates/UpdateData.cpp b/src/server/game/Entities/Object/Updates/UpdateData.cpp index e996db52c38..ee84b01e175 100644 --- a/src/server/game/Entities/Object/Updates/UpdateData.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateData.cpp @@ -25,7 +25,7 @@ #include "World.h" #include "zlib.h" -UpdateData::UpdateData() : m_blockCount(0) { } +UpdateData::UpdateData(uint16 map) : m_map(map), m_blockCount(0) { } void UpdateData::AddOutOfRangeGUID(std::set<uint64>& guids) { @@ -43,104 +43,24 @@ void UpdateData::AddUpdateBlock(const ByteBuffer &block) ++m_blockCount; } -void UpdateData::Compress(void* dst, uint32 *dst_size, void* src, int src_size) -{ - z_stream c_stream; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - // default Z_BEST_SPEED (1) - int z_res = deflateInit(&c_stream, sWorld->getIntConfig(CONFIG_COMPRESSION)); - if (z_res != Z_OK) - { - TC_LOG_ERROR("misc", "Can't compress update packet (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res)); - *dst_size = 0; - return; - } - - c_stream.next_out = (Bytef*)dst; - c_stream.avail_out = *dst_size; - c_stream.next_in = (Bytef*)src; - c_stream.avail_in = (uInt)src_size; - - z_res = deflate(&c_stream, Z_NO_FLUSH); - if (z_res != Z_OK) - { - TC_LOG_ERROR("misc", "Can't compress update packet (zlib: deflate) Error code: %i (%s)", z_res, zError(z_res)); - *dst_size = 0; - return; - } - - if (c_stream.avail_in != 0) - { - TC_LOG_ERROR("misc", "Can't compress update packet (zlib: deflate not greedy)"); - *dst_size = 0; - return; - } - - z_res = deflate(&c_stream, Z_FINISH); - if (z_res != Z_STREAM_END) - { - TC_LOG_ERROR("misc", "Can't compress update packet (zlib: deflate should report Z_STREAM_END instead %i (%s)", z_res, zError(z_res)); - *dst_size = 0; - return; - } - - z_res = deflateEnd(&c_stream); - if (z_res != Z_OK) - { - TC_LOG_ERROR("misc", "Can't compress update packet (zlib: deflateEnd) Error code: %i (%s)", z_res, zError(z_res)); - *dst_size = 0; - return; - } - - *dst_size = c_stream.total_out; -} - bool UpdateData::BuildPacket(WorldPacket* packet) { ASSERT(packet->empty()); // shouldn't happen + packet->Initialize(SMSG_UPDATE_OBJECT, 2 + 4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos()); - ByteBuffer buf(4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos()); - - buf << (uint32) (!m_outOfRangeGUIDs.empty() ? m_blockCount + 1 : m_blockCount); + *packet << uint16(m_map); + *packet << uint32(m_blockCount + (m_outOfRangeGUIDs.empty() ? 0 : 1)); if (!m_outOfRangeGUIDs.empty()) { - buf << (uint8) UPDATETYPE_OUT_OF_RANGE_OBJECTS; - buf << (uint32) m_outOfRangeGUIDs.size(); + *packet << uint8(UPDATETYPE_OUT_OF_RANGE_OBJECTS); + *packet << uint32(m_outOfRangeGUIDs.size()); for (std::set<uint64>::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); ++i) - { - buf.appendPackGUID(*i); - } - } - - buf.append(m_data); - - size_t pSize = buf.wpos(); // use real used data size - - if (pSize > 100) // compress large packets - { - uint32 destsize = compressBound(pSize); - packet->resize(destsize + sizeof(uint32)); - - packet->put<uint32>(0, pSize); - Compress(const_cast<uint8*>(packet->contents()) + sizeof(uint32), &destsize, (void*)buf.contents(), pSize); - if (destsize == 0) - return false; - - packet->resize(destsize + sizeof(uint32)); - packet->SetOpcode(SMSG_COMPRESSED_UPDATE_OBJECT); - } - else // send small packets without compression - { - packet->append(buf); - packet->SetOpcode(SMSG_UPDATE_OBJECT); + packet->appendPackGUID(*i); } + packet->append(m_data); return true; } @@ -149,5 +69,6 @@ void UpdateData::Clear() m_data.clear(); m_outOfRangeGUIDs.clear(); m_blockCount = 0; + m_map = 0; } diff --git a/src/server/game/Entities/Object/Updates/UpdateData.h b/src/server/game/Entities/Object/Updates/UpdateData.h index 1ec86192fab..e0666a1a717 100644 --- a/src/server/game/Entities/Object/Updates/UpdateData.h +++ b/src/server/game/Entities/Object/Updates/UpdateData.h @@ -27,33 +27,35 @@ class WorldPacket; enum OBJECT_UPDATE_TYPE { UPDATETYPE_VALUES = 0, - UPDATETYPE_MOVEMENT = 1, - UPDATETYPE_CREATE_OBJECT = 2, - UPDATETYPE_CREATE_OBJECT2 = 3, - UPDATETYPE_OUT_OF_RANGE_OBJECTS = 4, - UPDATETYPE_NEAR_OBJECTS = 5 + UPDATETYPE_CREATE_OBJECT = 1, + UPDATETYPE_CREATE_OBJECT2 = 2, + UPDATETYPE_OUT_OF_RANGE_OBJECTS = 3, }; enum OBJECT_UPDATE_FLAGS { - UPDATEFLAG_NONE = 0x0000, - UPDATEFLAG_SELF = 0x0001, - UPDATEFLAG_TRANSPORT = 0x0002, - UPDATEFLAG_HAS_TARGET = 0x0004, - UPDATEFLAG_UNKNOWN = 0x0008, - UPDATEFLAG_LOWGUID = 0x0010, - UPDATEFLAG_LIVING = 0x0020, - UPDATEFLAG_STATIONARY_POSITION = 0x0040, - UPDATEFLAG_VEHICLE = 0x0080, - UPDATEFLAG_POSITION = 0x0100, - UPDATEFLAG_ROTATION = 0x0200 + UPDATEFLAG_NONE = 0x0000, + UPDATEFLAG_SELF = 0x0001, + UPDATEFLAG_TRANSPORT = 0x0002, + UPDATEFLAG_HAS_TARGET = 0x0004, + UPDATEFLAG_UNKNOWN = 0x0008, + UPDATEFLAG_LOWGUID = 0x0010, + UPDATEFLAG_LIVING = 0x0020, + UPDATEFLAG_STATIONARY_POSITION = 0x0040, + UPDATEFLAG_VEHICLE = 0x0080, + UPDATEFLAG_GO_TRANSPORT_POSITION = 0x0100, + UPDATEFLAG_ROTATION = 0x0200, + UPDATEFLAG_UNK3 = 0x0400, + UPDATEFLAG_ANIMKITS = 0x0800, + UPDATEFLAG_UNK5 = 0x1000, + UPDATEFLAG_UNK6 = 0x2000, }; class UpdateData { public: - UpdateData(); - UpdateData(UpdateData&& right) : m_blockCount(right.m_blockCount), + UpdateData(uint16 map); + UpdateData(UpdateData&& right) : m_map(right.m_map), m_blockCount(right.m_blockCount), m_outOfRangeGUIDs(std::move(right.m_outOfRangeGUIDs)), m_data(std::move(right.m_data)) { @@ -69,12 +71,11 @@ class UpdateData std::set<uint64> const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; } protected: + uint16 m_map; uint32 m_blockCount; std::set<uint64> m_outOfRangeGUIDs; ByteBuffer m_data; - void Compress(void* dst, uint32 *dst_size, void* src, int src_size); - UpdateData(UpdateData const& right) = delete; UpdateData& operator=(UpdateData const& right) = delete; }; diff --git a/src/server/game/Entities/Object/Updates/UpdateFieldFlags.cpp b/src/server/game/Entities/Object/Updates/UpdateFieldFlags.cpp index 5629fef7d0c..0db2a312c9a 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFieldFlags.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateFieldFlags.cpp @@ -21,6 +21,8 @@ uint32 ItemUpdateFieldFlags[CONTAINER_END] = { UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID+1 + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA+1 UF_FLAG_PUBLIC, // OBJECT_FIELD_TYPE UF_FLAG_PUBLIC, // OBJECT_FIELD_ENTRY UF_FLAG_PUBLIC, // OBJECT_FIELD_SCALE_X @@ -77,12 +79,20 @@ uint32 ItemUpdateFieldFlags[CONTAINER_END] = UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_12_1 UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_12_1+1 UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_12_3 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_13_1 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_13_1+1 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_13_3 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_14_1 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_14_1+1 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_14_3 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_15_1 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_15_1+1 + UF_FLAG_PUBLIC, // ITEM_FIELD_ENCHANTMENT_15_3 UF_FLAG_PUBLIC, // ITEM_FIELD_PROPERTY_SEED UF_FLAG_PUBLIC, // ITEM_FIELD_RANDOM_PROPERTIES_ID UF_FLAG_OWNER | UF_FLAG_ITEM_OWNER, // ITEM_FIELD_DURABILITY UF_FLAG_OWNER | UF_FLAG_ITEM_OWNER, // ITEM_FIELD_MAXDURABILITY UF_FLAG_PUBLIC, // ITEM_FIELD_CREATE_PLAYED_TIME - UF_FLAG_NONE, // ITEM_FIELD_PAD UF_FLAG_PUBLIC, // CONTAINER_FIELD_NUM_SLOTS UF_FLAG_NONE, // CONTAINER_ALIGN_PAD UF_FLAG_PUBLIC, // CONTAINER_FIELD_SLOT_1 @@ -163,6 +173,8 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = { UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID+1 + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA+1 UF_FLAG_PUBLIC, // OBJECT_FIELD_TYPE UF_FLAG_PUBLIC, // OBJECT_FIELD_ENTRY UF_FLAG_PUBLIC, // OBJECT_FIELD_SCALE_X @@ -191,30 +203,22 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PUBLIC, // UNIT_FIELD_POWER3 UF_FLAG_PUBLIC, // UNIT_FIELD_POWER4 UF_FLAG_PUBLIC, // UNIT_FIELD_POWER5 - UF_FLAG_PUBLIC, // UNIT_FIELD_POWER6 - UF_FLAG_PUBLIC, // UNIT_FIELD_POWER7 UF_FLAG_PUBLIC, // UNIT_FIELD_MAXHEALTH UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER1 UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER2 UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER3 UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER4 UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER5 - UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER6 - UF_FLAG_PUBLIC, // UNIT_FIELD_MAXPOWER7 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+1 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+2 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+3 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+4 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+5 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+6 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+1 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+2 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+3 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+4 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+5 - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+6 + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+1 + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+2 + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+3 + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER+4 + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+1 + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+2 + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+3 + UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_UNUSED2, // UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER+4 UF_FLAG_PUBLIC, // UNIT_FIELD_LEVEL UF_FLAG_PUBLIC, // UNIT_FIELD_FACTIONTEMPLATE UF_FLAG_PUBLIC, // UNIT_VIRTUAL_ITEM_SLOT_ID @@ -228,7 +232,7 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // UNIT_FIELD_RANGEDATTACKTIME UF_FLAG_PUBLIC, // UNIT_FIELD_BOUNDINGRADIUS UF_FLAG_PUBLIC, // UNIT_FIELD_COMBATREACH - UF_FLAG_PUBLIC, // UNIT_FIELD_DISPLAYID + UF_FLAG_DYNAMIC, // UNIT_FIELD_DISPLAYID UF_FLAG_PUBLIC, // UNIT_FIELD_NATIVEDISPLAYID UF_FLAG_PUBLIC, // UNIT_FIELD_MOUNTDISPLAYID UF_FLAG_PRIVATE | UF_FLAG_OWNER | UF_FLAG_SPECIAL_INFO, // UNIT_FIELD_MINDAMAGE @@ -242,6 +246,7 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_OWNER, // UNIT_FIELD_PETNEXTLEVELEXP UF_FLAG_DYNAMIC, // UNIT_DYNAMIC_FLAGS UF_FLAG_PUBLIC, // UNIT_MOD_CAST_SPEED + UF_FLAG_PUBLIC, // UNIT_MOD_CAST_HASTE UF_FLAG_PUBLIC, // UNIT_CREATED_BY_SPELL UF_FLAG_DYNAMIC, // UNIT_NPC_FLAGS UF_FLAG_PUBLIC, // UNIT_NPC_EMOTESTATE @@ -285,10 +290,12 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_BASE_HEALTH UF_FLAG_PUBLIC, // UNIT_FIELD_BYTES_2 UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_ATTACK_POWER - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_ATTACK_POWER_MODS + UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_ATTACK_POWER_MOD_POS + UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_ATTACK_POWER_MOD_NEG UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_ATTACK_POWER_MULTIPLIER UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_RANGED_ATTACK_POWER - UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_RANGED_ATTACK_POWER_MODS + UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS + UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_RANGED_ATTACK_POWER_MOD_NEG UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_MINRANGEDDAMAGE UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_MAXRANGEDDAMAGE @@ -308,142 +315,269 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_POWER_COST_MULTIPLIER+6 UF_FLAG_PRIVATE | UF_FLAG_OWNER, // UNIT_FIELD_MAXHEALTHMODIFIER UF_FLAG_PUBLIC, // UNIT_FIELD_HOVERHEIGHT + UF_FLAG_PUBLIC, // UNIT_FIELD_MAXITEMLEVEL UF_FLAG_NONE, // UNIT_FIELD_PADDING UF_FLAG_PUBLIC, // PLAYER_DUEL_ARBITER UF_FLAG_PUBLIC, // PLAYER_DUEL_ARBITER+1 UF_FLAG_PUBLIC, // PLAYER_FLAGS - UF_FLAG_PUBLIC, // PLAYER_GUILDID UF_FLAG_PUBLIC, // PLAYER_GUILDRANK + UF_FLAG_PUBLIC, // PLAYER_GUILDDELETE_DATE + UF_FLAG_PUBLIC, // PLAYER_GUILDLEVEL UF_FLAG_PUBLIC, // PLAYER_BYTES UF_FLAG_PUBLIC, // PLAYER_BYTES_2 UF_FLAG_PUBLIC, // PLAYER_BYTES_3 UF_FLAG_PUBLIC, // PLAYER_DUEL_TEAM UF_FLAG_PUBLIC, // PLAYER_GUILD_TIMESTAMP UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_1_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_1_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_1_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_1_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_1_4 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_1_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_1_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_1_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_1_4 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_2_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_2_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_2_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_2_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_2_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_2_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_2_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_2_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_2_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_3_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_3_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_3_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_3_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_3_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_3_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_3_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_3_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_3_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_4_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_4_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_4_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_4_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_4_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_4_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_4_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_4_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_4_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_5_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_5_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_5_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_5_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_5_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_5_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_5_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_5_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_5_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_6_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_6_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_6_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_6_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_6_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_6_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_6_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_6_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_6_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_7_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_7_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_7_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_7_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_7_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_7_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_7_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_7_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_7_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_8_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_8_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_8_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_8_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_8_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_8_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_8_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_8_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_8_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_9_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_9_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_9_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_9_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_9_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_9_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_9_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_9_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_9_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_10_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_10_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_10_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_10_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_10_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_10_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_10_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_10_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_10_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_11_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_11_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_11_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_11_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_11_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_11_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_11_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_11_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_11_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_12_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_12_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_12_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_12_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_12_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_12_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_12_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_12_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_12_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_13_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_13_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_13_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_13_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_13_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_13_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_13_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_13_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_13_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_14_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_14_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_14_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_14_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_14_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_14_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_14_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_14_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_14_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_15_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_15_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_15_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_15_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_15_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_15_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_15_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_15_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_15_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_16_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_16_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_16_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_16_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_16_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_16_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_16_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_16_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_16_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_17_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_17_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_17_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_17_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_17_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_17_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_17_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_17_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_17_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_18_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_18_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_18_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_18_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_18_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_18_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_18_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_18_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_18_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_19_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_19_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_19_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_19_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_19_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_19_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_19_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_19_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_19_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_20_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_20_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_20_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_20_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_20_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_20_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_20_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_20_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_20_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_21_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_21_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_21_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_21_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_21_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_21_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_21_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_21_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_21_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_22_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_22_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_22_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_22_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_22_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_22_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_22_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_22_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_22_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_23_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_23_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_23_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_23_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_23_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_23_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_23_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_23_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_23_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_24_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_24_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_24_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_24_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_24_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_24_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_24_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_24_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_24_5 UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_25_1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_25_2 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_25_3 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_25_3+1 - UF_FLAG_PRIVATE, // PLAYER_QUEST_LOG_25_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_25_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_25_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_25_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_25_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_26_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_26_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_26_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_26_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_26_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_27_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_27_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_27_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_27_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_27_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_28_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_28_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_28_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_28_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_28_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_29_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_29_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_29_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_29_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_29_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_30_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_30_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_30_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_30_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_30_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_31_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_31_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_31_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_31_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_31_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_32_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_32_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_32_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_32_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_32_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_33_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_33_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_33_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_33_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_33_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_34_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_34_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_34_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_34_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_34_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_35_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_35_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_35_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_35_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_35_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_36_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_36_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_36_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_36_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_36_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_37_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_37_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_37_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_37_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_37_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_38_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_38_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_38_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_38_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_38_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_39_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_39_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_39_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_39_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_39_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_40_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_40_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_40_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_40_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_40_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_41_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_41_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_41_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_41_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_41_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_42_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_42_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_42_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_42_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_42_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_43_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_43_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_43_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_43_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_43_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_44_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_44_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_44_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_44_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_44_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_45_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_45_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_45_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_45_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_45_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_46_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_46_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_46_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_46_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_46_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_47_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_47_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_47_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_47_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_47_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_48_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_48_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_48_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_48_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_48_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_49_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_49_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_49_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_49_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_49_5 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_50_1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_50_2 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_50_3 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_50_3+1 + UF_FLAG_PARTY_MEMBER, // PLAYER_QUEST_LOG_50_5 UF_FLAG_PUBLIC, // PLAYER_VISIBLE_ITEM_1_ENTRYID UF_FLAG_PUBLIC, // PLAYER_VISIBLE_ITEM_1_ENCHANTMENT UF_FLAG_PUBLIC, // PLAYER_VISIBLE_ITEM_2_ENTRYID @@ -657,134 +791,6 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER_FIELD_VENDORBUYBACK_SLOT_1+21 UF_FLAG_PRIVATE, // PLAYER_FIELD_VENDORBUYBACK_SLOT_1+22 UF_FLAG_PRIVATE, // PLAYER_FIELD_VENDORBUYBACK_SLOT_1+23 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+1 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+2 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+3 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+4 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+5 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+6 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+7 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+8 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+9 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+10 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+11 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+12 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+13 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+14 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+15 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+16 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+17 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+18 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+19 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+20 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+21 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+22 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+23 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+24 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+25 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+26 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+27 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+28 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+29 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+30 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+31 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+32 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+33 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+34 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+35 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+36 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+37 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+38 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+39 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+40 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+41 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+42 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+43 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+44 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+45 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+46 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+47 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+48 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+49 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+50 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+51 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+52 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+53 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+54 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+55 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+56 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+57 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+58 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+59 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+60 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+61 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+62 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KEYRING_SLOT_1+63 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+1 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+2 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+3 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+4 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+5 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+6 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+7 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+8 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+9 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+10 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+11 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+12 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+13 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+14 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+15 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+16 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+17 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+18 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+19 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+20 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+21 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+22 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+23 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+24 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+25 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+26 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+27 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+28 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+29 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+30 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+31 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+32 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+33 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+34 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+35 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+36 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+37 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+38 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+39 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+40 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+41 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+42 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+43 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+44 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+45 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+46 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+47 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+48 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+49 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+50 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+51 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+52 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+53 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+54 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+55 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+56 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+57 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+58 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+59 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+60 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+61 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+62 - UF_FLAG_PRIVATE, // PLAYER_FIELD_CURRENCYTOKEN_SLOT_1+63 UF_FLAG_PRIVATE, // PLAYER_FARSIGHT UF_FLAG_PRIVATE, // PLAYER_FARSIGHT+1 UF_FLAG_PRIVATE, // PLAYER__FIELD_KNOWN_TITLES @@ -793,403 +799,402 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER__FIELD_KNOWN_TITLES1+1 UF_FLAG_PRIVATE, // PLAYER__FIELD_KNOWN_TITLES2 UF_FLAG_PRIVATE, // PLAYER__FIELD_KNOWN_TITLES2+1 - UF_FLAG_PRIVATE, // PLAYER_FIELD_KNOWN_CURRENCIES - UF_FLAG_PRIVATE, // PLAYER_FIELD_KNOWN_CURRENCIES+1 + UF_FLAG_PRIVATE, // PLAYER__FIELD_KNOWN_TITLES3 + UF_FLAG_PRIVATE, // PLAYER__FIELD_KNOWN_TITLES3+1 UF_FLAG_PRIVATE, // PLAYER_XP UF_FLAG_PRIVATE, // PLAYER_NEXT_LEVEL_XP - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+1 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+2 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+3 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+4 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+5 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+6 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+7 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+8 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+9 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+10 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+11 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+12 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+13 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+14 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+15 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+16 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+17 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+18 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+19 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+20 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+21 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+22 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+23 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+24 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+25 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+26 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+27 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+28 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+29 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+30 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+31 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+32 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+33 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+34 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+35 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+36 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+37 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+38 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+39 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+40 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+41 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+42 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+43 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+44 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+45 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+46 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+47 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+48 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+49 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+50 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+51 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+52 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+53 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+54 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+55 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+56 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+57 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+58 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+59 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+60 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+61 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+62 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+63 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+64 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+65 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+66 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+67 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+68 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+69 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+70 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+71 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+72 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+73 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+74 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+75 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+76 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+77 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+78 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+79 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+80 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+81 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+82 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+83 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+84 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+85 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+86 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+87 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+88 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+89 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+90 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+91 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+92 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+93 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+94 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+95 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+96 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+97 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+98 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+99 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+100 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+101 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+102 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+103 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+104 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+105 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+106 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+107 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+108 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+109 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+110 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+111 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+112 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+113 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+114 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+115 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+116 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+117 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+118 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+119 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+120 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+121 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+122 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+123 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+124 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+125 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+126 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+127 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+128 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+129 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+130 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+131 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+132 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+133 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+134 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+135 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+136 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+137 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+138 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+139 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+140 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+141 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+142 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+143 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+144 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+145 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+146 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+147 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+148 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+149 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+150 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+151 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+152 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+153 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+154 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+155 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+156 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+157 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+158 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+159 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+160 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+161 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+162 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+163 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+164 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+165 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+166 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+167 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+168 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+169 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+170 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+171 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+172 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+173 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+174 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+175 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+176 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+177 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+178 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+179 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+180 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+181 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+182 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+183 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+184 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+185 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+186 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+187 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+188 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+189 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+190 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+191 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+192 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+193 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+194 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+195 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+196 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+197 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+198 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+199 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+200 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+201 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+202 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+203 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+204 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+205 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+206 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+207 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+208 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+209 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+210 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+211 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+212 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+213 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+214 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+215 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+216 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+217 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+218 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+219 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+220 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+221 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+222 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+223 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+224 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+225 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+226 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+227 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+228 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+229 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+230 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+231 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+232 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+233 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+234 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+235 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+236 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+237 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+238 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+239 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+240 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+241 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+242 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+243 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+244 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+245 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+246 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+247 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+248 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+249 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+250 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+251 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+252 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+253 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+254 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+255 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+256 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+257 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+258 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+259 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+260 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+261 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+262 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+263 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+264 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+265 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+266 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+267 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+268 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+269 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+270 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+271 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+272 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+273 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+274 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+275 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+276 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+277 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+278 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+279 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+280 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+281 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+282 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+283 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+284 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+285 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+286 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+287 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+288 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+289 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+290 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+291 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+292 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+293 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+294 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+295 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+296 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+297 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+298 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+299 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+300 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+301 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+302 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+303 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+304 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+305 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+306 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+307 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+308 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+309 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+310 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+311 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+312 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+313 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+314 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+315 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+316 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+317 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+318 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+319 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+320 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+321 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+322 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+323 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+324 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+325 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+326 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+327 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+328 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+329 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+330 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+331 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+332 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+333 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+334 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+335 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+336 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+337 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+338 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+339 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+340 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+341 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+342 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+343 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+344 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+345 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+346 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+347 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+348 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+349 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+350 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+351 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+352 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+353 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+354 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+355 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+356 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+357 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+358 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+359 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+360 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+361 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+362 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+363 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+364 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+365 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+366 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+367 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+368 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+369 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+370 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+371 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+372 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+373 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+374 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+375 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+376 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+377 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+378 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+379 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+380 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+381 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+382 - UF_FLAG_PRIVATE, // PLAYER_SKILL_INFO_1_1+383 - UF_FLAG_PRIVATE, // PLAYER_CHARACTER_POINTS1 - UF_FLAG_PRIVATE, // PLAYER_CHARACTER_POINTS2 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+1 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+2 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+3 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+4 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+5 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+6 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+7 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+8 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+9 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+10 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+11 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+12 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+13 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+14 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+15 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+16 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+17 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+18 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+19 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+20 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+21 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+22 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+23 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+24 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+25 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+26 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+27 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+28 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+29 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+30 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+31 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+32 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+33 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+34 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+35 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+36 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+37 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+38 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+39 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+40 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+41 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+42 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+43 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+44 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+45 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+46 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+47 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+48 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+49 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+50 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+51 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+52 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+53 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+54 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+55 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+56 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+57 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+58 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+59 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+60 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+61 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+62 + UF_FLAG_PRIVATE, // PLAYER_SKILL_LINEID_0+63 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+1 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+2 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+3 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+4 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+5 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+6 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+7 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+8 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+9 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+10 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+11 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+12 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+13 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+14 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+15 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+16 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+17 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+18 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+19 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+20 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+21 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+22 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+23 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+24 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+25 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+26 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+27 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+28 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+29 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+30 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+31 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+32 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+33 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+34 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+35 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+36 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+37 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+38 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+39 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+40 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+41 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+42 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+43 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+44 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+45 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+46 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+47 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+48 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+49 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+50 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+51 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+52 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+53 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+54 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+55 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+56 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+57 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+58 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+59 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+60 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+61 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+62 + UF_FLAG_PRIVATE, // PLAYER_SKILL_STEP_0+63 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+1 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+2 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+3 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+4 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+5 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+6 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+7 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+8 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+9 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+10 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+11 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+12 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+13 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+14 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+15 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+16 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+17 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+18 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+19 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+20 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+21 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+22 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+23 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+24 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+25 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+26 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+27 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+28 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+29 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+30 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+31 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+32 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+33 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+34 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+35 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+36 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+37 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+38 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+39 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+40 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+41 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+42 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+43 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+44 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+45 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+46 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+47 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+48 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+49 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+50 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+51 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+52 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+53 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+54 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+55 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+56 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+57 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+58 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+59 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+60 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+61 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+62 + UF_FLAG_PRIVATE, // PLAYER_SKILL_RANK_0+63 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+1 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+2 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+3 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+4 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+5 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+6 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+7 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+8 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+9 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+10 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+11 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+12 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+13 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+14 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+15 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+16 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+17 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+18 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+19 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+20 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+21 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+22 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+23 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+24 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+25 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+26 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+27 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+28 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+29 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+30 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+31 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+32 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+33 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+34 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+35 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+36 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+37 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+38 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+39 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+40 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+41 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+42 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+43 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+44 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+45 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+46 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+47 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+48 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+49 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+50 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+51 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+52 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+53 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+54 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+55 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+56 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+57 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+58 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+59 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+60 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+61 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+62 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MAX_RANK_0+63 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+1 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+2 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+3 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+4 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+5 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+6 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+7 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+8 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+9 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+10 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+11 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+12 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+13 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+14 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+15 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+16 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+17 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+18 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+19 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+20 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+21 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+22 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+23 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+24 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+25 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+26 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+27 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+28 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+29 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+30 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+31 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+32 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+33 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+34 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+35 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+36 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+37 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+38 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+39 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+40 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+41 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+42 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+43 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+44 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+45 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+46 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+47 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+48 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+49 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+50 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+51 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+52 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+53 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+54 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+55 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+56 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+57 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+58 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+59 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+60 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+61 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+62 + UF_FLAG_PRIVATE, // PLAYER_SKILL_MODIFIER_0+63 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+1 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+2 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+3 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+4 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+5 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+6 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+7 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+8 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+9 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+10 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+11 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+12 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+13 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+14 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+15 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+16 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+17 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+18 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+19 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+20 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+21 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+22 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+23 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+24 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+25 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+26 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+27 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+28 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+29 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+30 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+31 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+32 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+33 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+34 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+35 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+36 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+37 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+38 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+39 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+40 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+41 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+42 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+43 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+44 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+45 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+46 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+47 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+48 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+49 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+50 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+51 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+52 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+53 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+54 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+55 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+56 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+57 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+58 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+59 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+60 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+61 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+62 + UF_FLAG_PRIVATE, // PLAYER_SKILL_TALENT_0+63 + UF_FLAG_PRIVATE, // PLAYER_CHARACTER_POINTS UF_FLAG_PRIVATE, // PLAYER_TRACK_CREATURES UF_FLAG_PRIVATE, // PLAYER_TRACK_RESOURCES + UF_FLAG_PRIVATE, // PLAYER_EXPERTISE + UF_FLAG_PRIVATE, // PLAYER_OFFHAND_EXPERTISE UF_FLAG_PRIVATE, // PLAYER_BLOCK_PERCENTAGE UF_FLAG_PRIVATE, // PLAYER_DODGE_PERCENTAGE UF_FLAG_PRIVATE, // PLAYER_PARRY_PERCENTAGE - UF_FLAG_PRIVATE, // PLAYER_EXPERTISE - UF_FLAG_PRIVATE, // PLAYER_OFFHAND_EXPERTISE UF_FLAG_PRIVATE, // PLAYER_CRIT_PERCENTAGE UF_FLAG_PRIVATE, // PLAYER_RANGED_CRIT_PERCENTAGE UF_FLAG_PRIVATE, // PLAYER_OFFHAND_CRIT_PERCENTAGE @@ -1202,6 +1207,7 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER_SPELL_CRIT_PERCENTAGE1+6 UF_FLAG_PRIVATE, // PLAYER_SHIELD_BLOCK UF_FLAG_PRIVATE, // PLAYER_SHIELD_BLOCK_CRIT_PERCENTAGE + UF_FLAG_PRIVATE, // PLAYER_MASTERY UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1 UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+1 UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+2 @@ -1330,8 +1336,37 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+125 UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+126 UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+127 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+128 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+129 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+130 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+131 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+132 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+133 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+134 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+135 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+136 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+137 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+138 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+139 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+140 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+141 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+142 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+143 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+144 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+145 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+146 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+147 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+148 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+149 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+150 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+151 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+152 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+153 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+154 + UF_FLAG_PRIVATE, // PLAYER_EXPLORED_ZONES_1+155 UF_FLAG_PRIVATE, // PLAYER_REST_STATE_EXPERIENCE UF_FLAG_PRIVATE, // PLAYER_FIELD_COINAGE + UF_FLAG_PRIVATE, // PLAYER_FIELD_COINAGE+1 UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_DAMAGE_DONE_POS UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_DAMAGE_DONE_POS+1 UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_DAMAGE_DONE_POS+2 @@ -1356,10 +1391,14 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_HEALING_DONE_POS UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_HEALING_PCT UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_HEALING_DONE_PCT + UF_FLAG_PRIVATE, // PLAYER_FIELD_WEAPON_DMG_MULTIPLIERS + UF_FLAG_PRIVATE, // PLAYER_FIELD_WEAPON_DMG_MULTIPLIERS+1 + UF_FLAG_PRIVATE, // PLAYER_FIELD_WEAPON_DMG_MULTIPLIERS+2 + UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_SPELL_POWER_PCT + UF_FLAG_PRIVATE, // PLAYER_FIELD_OVERRIDE_SPELL_POWER_BY_AP_PCT UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_TARGET_RESISTANCE UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE UF_FLAG_PRIVATE, // PLAYER_FIELD_BYTES - UF_FLAG_PRIVATE, // PLAYER_AMMO_ID UF_FLAG_PRIVATE, // PLAYER_SELF_RES_SPELL UF_FLAG_PRIVATE, // PLAYER_FIELD_PVP_MEDALS UF_FLAG_PRIVATE, // PLAYER_FIELD_BUYBACK_PRICE_1 @@ -1387,8 +1426,6 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER_FIELD_BUYBACK_TIMESTAMP_1+10 UF_FLAG_PRIVATE, // PLAYER_FIELD_BUYBACK_TIMESTAMP_1+11 UF_FLAG_PRIVATE, // PLAYER_FIELD_KILLS - UF_FLAG_PRIVATE, // PLAYER_FIELD_TODAY_CONTRIBUTION - UF_FLAG_PRIVATE, // PLAYER_FIELD_YESTERDAY_CONTRIBUTION UF_FLAG_PRIVATE, // PLAYER_FIELD_LIFETIME_HONORBALE_KILLS UF_FLAG_PRIVATE, // PLAYER_FIELD_BYTES2 UF_FLAG_PRIVATE, // PLAYER_FIELD_WATCHED_FACTION_INDEX @@ -1417,6 +1454,7 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER_FIELD_COMBAT_RATING_1+22 UF_FLAG_PRIVATE, // PLAYER_FIELD_COMBAT_RATING_1+23 UF_FLAG_PRIVATE, // PLAYER_FIELD_COMBAT_RATING_1+24 + UF_FLAG_PRIVATE, // PLAYER_FIELD_COMBAT_RATING_1+25 UF_FLAG_PRIVATE, // PLAYER_FIELD_ARENA_TEAM_INFO_1_1 UF_FLAG_PRIVATE, // PLAYER_FIELD_ARENA_TEAM_INFO_1_1+1 UF_FLAG_PRIVATE, // PLAYER_FIELD_ARENA_TEAM_INFO_1_1+2 @@ -1438,8 +1476,7 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER_FIELD_ARENA_TEAM_INFO_1_1+18 UF_FLAG_PRIVATE, // PLAYER_FIELD_ARENA_TEAM_INFO_1_1+19 UF_FLAG_PRIVATE, // PLAYER_FIELD_ARENA_TEAM_INFO_1_1+20 - UF_FLAG_PRIVATE, // PLAYER_FIELD_HONOR_CURRENCY - UF_FLAG_PRIVATE, // PLAYER_FIELD_ARENA_CURRENCY + UF_FLAG_PRIVATE, // PLAYER_FIELD_BATTLEGROUND_RATING UF_FLAG_PRIVATE, // PLAYER_FIELD_MAX_LEVEL UF_FLAG_PRIVATE, // PLAYER_FIELD_DAILY_QUESTS_1 UF_FLAG_PRIVATE, // PLAYER_FIELD_DAILY_QUESTS_1+1 @@ -1479,20 +1516,53 @@ uint32 UnitUpdateFieldFlags[PLAYER_END] = UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPH_SLOTS_1+3 UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPH_SLOTS_1+4 UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPH_SLOTS_1+5 + UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPH_SLOTS_1+6 + UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPH_SLOTS_1+7 + UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPH_SLOTS_1+8 UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1 UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1+1 UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1+2 UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1+3 UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1+4 UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1+5 + UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1+6 + UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1+7 + UF_FLAG_PRIVATE, // PLAYER_FIELD_GLYPHS_1+8 UF_FLAG_PRIVATE, // PLAYER_GLYPHS_ENABLED UF_FLAG_PRIVATE, // PLAYER_PET_SPELL_POWER + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESEARCHING_1 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESEARCHING_1+1 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESEARCHING_1+2 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESEARCHING_1+3 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESEARCHING_1+4 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESEARCHING_1+5 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESEARCHING_1+6 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESEARCHING_1+7 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESERACH_SITE_1 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESERACH_SITE_1+1 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESERACH_SITE_1+2 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESERACH_SITE_1+3 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESERACH_SITE_1+4 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESERACH_SITE_1+5 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESERACH_SITE_1+6 + UF_FLAG_PRIVATE, // PLAYER_FIELD_RESERACH_SITE_1+7 + UF_FLAG_PRIVATE, // PLAYER_PROFESSION_SKILL_LINE_1 + UF_FLAG_PRIVATE, // PLAYER_PROFESSION_SKILL_LINE_1+1 + UF_FLAG_PRIVATE, // PLAYER_FIELD_UI_HIT_MODIFIER + UF_FLAG_PRIVATE, // PLAYER_FIELD_UI_SPELL_HIT_MODIFIER + UF_FLAG_PRIVATE, // PLAYER_FIELD_HOME_REALM_TIME_OFFSET + UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_HASTE + UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_RANGED_HASTE + UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_PET_HASTE + UF_FLAG_PRIVATE, // PLAYER_FIELD_MOD_HASTE_REGEN }; uint32 GameObjectUpdateFieldFlags[GAMEOBJECT_END] = { UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID+1 + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA+1 UF_FLAG_PUBLIC, // OBJECT_FIELD_TYPE UF_FLAG_PUBLIC, // OBJECT_FIELD_ENTRY UF_FLAG_PUBLIC, // OBJECT_FIELD_SCALE_X @@ -1515,13 +1585,15 @@ uint32 DynamicObjectUpdateFieldFlags[DYNAMICOBJECT_END] = { UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID+1 + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA+1 UF_FLAG_PUBLIC, // OBJECT_FIELD_TYPE UF_FLAG_PUBLIC, // OBJECT_FIELD_ENTRY UF_FLAG_PUBLIC, // OBJECT_FIELD_SCALE_X UF_FLAG_NONE, // OBJECT_FIELD_PADDING UF_FLAG_PUBLIC, // DYNAMICOBJECT_CASTER UF_FLAG_PUBLIC, // DYNAMICOBJECT_CASTER+1 - UF_FLAG_PUBLIC, // DYNAMICOBJECT_BYTES + UF_FLAG_DYNAMIC, // DYNAMICOBJECT_BYTES UF_FLAG_PUBLIC, // DYNAMICOBJECT_SPELLID UF_FLAG_PUBLIC, // DYNAMICOBJECT_RADIUS UF_FLAG_PUBLIC, // DYNAMICOBJECT_CASTTIME @@ -1531,6 +1603,8 @@ uint32 CorpseUpdateFieldFlags[CORPSE_END] = { UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID+1 + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA+1 UF_FLAG_PUBLIC, // OBJECT_FIELD_TYPE UF_FLAG_PUBLIC, // OBJECT_FIELD_ENTRY UF_FLAG_PUBLIC, // OBJECT_FIELD_SCALE_X @@ -1561,8 +1635,24 @@ uint32 CorpseUpdateFieldFlags[CORPSE_END] = UF_FLAG_PUBLIC, // CORPSE_FIELD_ITEM+18 UF_FLAG_PUBLIC, // CORPSE_FIELD_BYTES_1 UF_FLAG_PUBLIC, // CORPSE_FIELD_BYTES_2 - UF_FLAG_PUBLIC, // CORPSE_FIELD_GUILD UF_FLAG_PUBLIC, // CORPSE_FIELD_FLAGS UF_FLAG_DYNAMIC, // CORPSE_FIELD_DYNAMIC_FLAGS - UF_FLAG_NONE, // CORPSE_FIELD_PAD +}; + +uint32 AreaTriggerUpdateFieldFlags[AREATRIGGER_END] = +{ + UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID + UF_FLAG_PUBLIC, // OBJECT_FIELD_GUID+1 + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA + UF_FLAG_PUBLIC, // OBJECT_FIELD_DATA+1 + UF_FLAG_PUBLIC, // OBJECT_FIELD_TYPE + UF_FLAG_PUBLIC, // OBJECT_FIELD_ENTRY + UF_FLAG_PUBLIC, // OBJECT_FIELD_SCALE_X + UF_FLAG_NONE, // OBJECT_FIELD_PADDING + UF_FLAG_PUBLIC, // AREATRIGGER_SPELLID + UF_FLAG_PUBLIC, // AREATRIGGER_SPELLVISUALID + UF_FLAG_PUBLIC, // AREATRIGGER_DURATION + UF_FLAG_PUBLIC, // AREATRIGGER_FINAL_POS + UF_FLAG_PUBLIC, // AREATRIGGER_FINAL_POS+1 + UF_FLAG_PUBLIC, // AREATRIGGER_FINAL_POS+2 }; diff --git a/src/server/game/Entities/Object/Updates/UpdateFieldFlags.h b/src/server/game/Entities/Object/Updates/UpdateFieldFlags.h index 6d168cd56c4..b0e6bb6afa2 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFieldFlags.h +++ b/src/server/game/Entities/Object/Updates/UpdateFieldFlags.h @@ -40,5 +40,6 @@ extern uint32 UnitUpdateFieldFlags[PLAYER_END]; extern uint32 GameObjectUpdateFieldFlags[GAMEOBJECT_END]; extern uint32 DynamicObjectUpdateFieldFlags[DYNAMICOBJECT_END]; extern uint32 CorpseUpdateFieldFlags[CORPSE_END]; +extern uint32 AreaTriggerUpdateFieldFlags[AREATRIGGER_END]; #endif // _UPDATEFIELDFLAGS_H diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h index 2838ee31d81..880eb68bb89 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.h +++ b/src/server/game/Entities/Object/Updates/UpdateFields.h @@ -16,418 +16,550 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _UPDATEFIELDS_AUTO_H -#define _UPDATEFIELDS_AUTO_H +#ifndef _UPDATEFIELDS_H +#define _UPDATEFIELDS_H -// Auto generated for version 3, 3, 5, 12340 +// Auto generated for version 4, 3, 4, 15595 enum EObjectFields { - OBJECT_FIELD_GUID = 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - OBJECT_FIELD_TYPE = 0x0002, // Size: 1, Type: INT, Flags: PUBLIC - OBJECT_FIELD_ENTRY = 0x0003, // Size: 1, Type: INT, Flags: PUBLIC - OBJECT_FIELD_SCALE_X = 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC - OBJECT_FIELD_PADDING = 0x0005, // Size: 1, Type: INT, Flags: NONE - OBJECT_END = 0x0006 + OBJECT_FIELD_GUID = 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + OBJECT_FIELD_DATA = 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC + OBJECT_FIELD_TYPE = 0x0004, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + OBJECT_FIELD_ENTRY = 0x0005, // Size: 1, Type: INT, Flags: PUBLIC + OBJECT_FIELD_SCALE_X = 0x0006, // Size: 1, Type: FLOAT, Flags: PUBLIC + OBJECT_FIELD_PADDING = 0x0007, // Size: 1, Type: INT, Flags: NONE + OBJECT_END = 0x0008 }; enum EItemFields { - ITEM_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - ITEM_FIELD_CONTAINED = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC - ITEM_FIELD_CREATOR = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PUBLIC - ITEM_FIELD_GIFTCREATOR = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC - ITEM_FIELD_STACK_COUNT = OBJECT_END + 0x0008, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_DURATION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_SPELL_CHARGES = OBJECT_END + 0x000A, // Size: 5, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_FLAGS = OBJECT_END + 0x000F, // Size: 1, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_1_1 = OBJECT_END + 0x0010, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_1_3 = OBJECT_END + 0x0012, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_2_1 = OBJECT_END + 0x0013, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_2_3 = OBJECT_END + 0x0015, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_3_1 = OBJECT_END + 0x0016, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_3_3 = OBJECT_END + 0x0018, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_4_1 = OBJECT_END + 0x0019, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_4_3 = OBJECT_END + 0x001B, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_5_1 = OBJECT_END + 0x001C, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_5_3 = OBJECT_END + 0x001E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_6_1 = OBJECT_END + 0x001F, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_6_3 = OBJECT_END + 0x0021, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_7_1 = OBJECT_END + 0x0022, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_7_3 = OBJECT_END + 0x0024, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_8_1 = OBJECT_END + 0x0025, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_8_3 = OBJECT_END + 0x0027, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_9_1 = OBJECT_END + 0x0028, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_9_3 = OBJECT_END + 0x002A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_10_1 = OBJECT_END + 0x002B, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_10_3 = OBJECT_END + 0x002D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_11_1 = OBJECT_END + 0x002E, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_11_3 = OBJECT_END + 0x0030, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_12_1 = OBJECT_END + 0x0031, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_12_3 = OBJECT_END + 0x0033, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_PROPERTY_SEED = OBJECT_END + 0x0034, // Size: 1, Type: INT, Flags: PUBLIC - ITEM_FIELD_RANDOM_PROPERTIES_ID = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC - ITEM_FIELD_DURABILITY = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_MAXDURABILITY = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_CREATE_PLAYED_TIME = OBJECT_END + 0x0038, // Size: 1, Type: INT, Flags: PUBLIC - ITEM_FIELD_PAD = OBJECT_END + 0x0039, // Size: 1, Type: INT, Flags: NONE - ITEM_END = OBJECT_END + 0x003A + ITEM_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + ITEM_FIELD_CONTAINED = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC + ITEM_FIELD_CREATOR = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PUBLIC + ITEM_FIELD_GIFTCREATOR = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC + ITEM_FIELD_STACK_COUNT = OBJECT_END + 0x0008, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_DURATION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_SPELL_CHARGES = OBJECT_END + 0x000A, // Size: 5, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_FLAGS = OBJECT_END + 0x000F, // Size: 1, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_1_1 = OBJECT_END + 0x0010, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_1_3 = OBJECT_END + 0x0012, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_2_1 = OBJECT_END + 0x0013, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_2_3 = OBJECT_END + 0x0015, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_3_1 = OBJECT_END + 0x0016, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_3_3 = OBJECT_END + 0x0018, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_4_1 = OBJECT_END + 0x0019, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_4_3 = OBJECT_END + 0x001B, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_5_1 = OBJECT_END + 0x001C, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_5_3 = OBJECT_END + 0x001E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_6_1 = OBJECT_END + 0x001F, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_6_3 = OBJECT_END + 0x0021, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_7_1 = OBJECT_END + 0x0022, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_7_3 = OBJECT_END + 0x0024, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_8_1 = OBJECT_END + 0x0025, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_8_3 = OBJECT_END + 0x0027, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_9_1 = OBJECT_END + 0x0028, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_9_3 = OBJECT_END + 0x002A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_10_1 = OBJECT_END + 0x002B, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_10_3 = OBJECT_END + 0x002D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_11_1 = OBJECT_END + 0x002E, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_11_3 = OBJECT_END + 0x0030, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_12_1 = OBJECT_END + 0x0031, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_12_3 = OBJECT_END + 0x0033, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_13_1 = OBJECT_END + 0x0034, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_13_3 = OBJECT_END + 0x0036, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_14_1 = OBJECT_END + 0x0037, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_14_3 = OBJECT_END + 0x0039, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_15_1 = OBJECT_END + 0x003A, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_15_3 = OBJECT_END + 0x003C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_PROPERTY_SEED = OBJECT_END + 0x003D, // Size: 1, Type: INT, Flags: PUBLIC + ITEM_FIELD_RANDOM_PROPERTIES_ID = OBJECT_END + 0x003E, // Size: 1, Type: INT, Flags: PUBLIC + ITEM_FIELD_DURABILITY = OBJECT_END + 0x003F, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_MAXDURABILITY = OBJECT_END + 0x0040, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_CREATE_PLAYED_TIME = OBJECT_END + 0x0041, // Size: 1, Type: INT, Flags: PUBLIC + ITEM_END = OBJECT_END + 0x0042, }; enum EContainerFields { - CONTAINER_FIELD_NUM_SLOTS = ITEM_END + 0x0000, // Size: 1, Type: INT, Flags: PUBLIC - CONTAINER_ALIGN_PAD = ITEM_END + 0x0001, // Size: 1, Type: BYTES, Flags: NONE - CONTAINER_FIELD_SLOT_1 = ITEM_END + 0x0002, // Size: 72, Type: LONG, Flags: PUBLIC - CONTAINER_END = ITEM_END + 0x004A + CONTAINER_FIELD_NUM_SLOTS = ITEM_END + 0x0000, // Size: 1, Type: INT, Flags: PUBLIC + CONTAINER_ALIGN_PAD = ITEM_END + 0x0001, // Size: 1, Type: BYTES, Flags: NONE + CONTAINER_FIELD_SLOT_1 = ITEM_END + 0x0002, // Size: 72, Type: LONG, Flags: PUBLIC + CONTAINER_END = ITEM_END + 0x004A }; enum EUnitFields { - UNIT_FIELD_CHARM = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_SUMMON = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_CRITTER = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PRIVATE - UNIT_FIELD_CHARMEDBY = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_SUMMONEDBY = OBJECT_END + 0x0008, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_CREATEDBY = OBJECT_END + 0x000A, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_TARGET = OBJECT_END + 0x000C, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_CHANNEL_OBJECT = OBJECT_END + 0x000E, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_CHANNEL_SPELL = OBJECT_END + 0x0010, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_BYTES_0 = OBJECT_END + 0x0011, // Size: 1, Type: BYTES, Flags: PUBLIC - UNIT_FIELD_HEALTH = OBJECT_END + 0x0012, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER1 = OBJECT_END + 0x0013, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER2 = OBJECT_END + 0x0014, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER3 = OBJECT_END + 0x0015, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER4 = OBJECT_END + 0x0016, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER5 = OBJECT_END + 0x0017, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER6 = OBJECT_END + 0x0018, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER7 = OBJECT_END + 0x0019, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXHEALTH = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER1 = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER2 = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER3 = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER4 = OBJECT_END + 0x001E, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER5 = OBJECT_END + 0x001F, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER6 = OBJECT_END + 0x0020, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER7 = OBJECT_END + 0x0021, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER = OBJECT_END + 0x0022, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER = OBJECT_END + 0x0029, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_LEVEL = OBJECT_END + 0x0030, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_FACTIONTEMPLATE = OBJECT_END + 0x0031, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_VIRTUAL_ITEM_SLOT_ID = OBJECT_END + 0x0032, // Size: 3, Type: INT, Flags: PUBLIC - UNIT_FIELD_FLAGS = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_FLAGS_2 = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_AURASTATE = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_BASEATTACKTIME = OBJECT_END + 0x0038, // Size: 2, Type: INT, Flags: PUBLIC - UNIT_FIELD_RANGEDATTACKTIME = OBJECT_END + 0x003A, // Size: 1, Type: INT, Flags: PRIVATE - UNIT_FIELD_BOUNDINGRADIUS = OBJECT_END + 0x003B, // Size: 1, Type: FLOAT, Flags: PUBLIC - UNIT_FIELD_COMBATREACH = OBJECT_END + 0x003C, // Size: 1, Type: FLOAT, Flags: PUBLIC - UNIT_FIELD_DISPLAYID = OBJECT_END + 0x003D, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_NATIVEDISPLAYID = OBJECT_END + 0x003E, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MOUNTDISPLAYID = OBJECT_END + 0x003F, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MINDAMAGE = OBJECT_END + 0x0040, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_MAXDAMAGE = OBJECT_END + 0x0041, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_MINOFFHANDDAMAGE = OBJECT_END + 0x0042, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_MAXOFFHANDDAMAGE = OBJECT_END + 0x0043, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_BYTES_1 = OBJECT_END + 0x0044, // Size: 1, Type: BYTES, Flags: PUBLIC - UNIT_FIELD_PETNUMBER = OBJECT_END + 0x0045, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_PET_NAME_TIMESTAMP = OBJECT_END + 0x0046, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_PETEXPERIENCE = OBJECT_END + 0x0047, // Size: 1, Type: INT, Flags: OWNER - UNIT_FIELD_PETNEXTLEVELEXP = OBJECT_END + 0x0048, // Size: 1, Type: INT, Flags: OWNER - UNIT_DYNAMIC_FLAGS = OBJECT_END + 0x0049, // Size: 1, Type: INT, Flags: DYNAMIC - UNIT_MOD_CAST_SPEED = OBJECT_END + 0x004A, // Size: 1, Type: FLOAT, Flags: PUBLIC - UNIT_CREATED_BY_SPELL = OBJECT_END + 0x004B, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_NPC_FLAGS = OBJECT_END + 0x004C, // Size: 1, Type: INT, Flags: DYNAMIC - UNIT_NPC_EMOTESTATE = OBJECT_END + 0x004D, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_STAT0 = OBJECT_END + 0x004E, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_STAT1 = OBJECT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_STAT2 = OBJECT_END + 0x0050, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_STAT3 = OBJECT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_STAT4 = OBJECT_END + 0x0052, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT0 = OBJECT_END + 0x0053, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT1 = OBJECT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT2 = OBJECT_END + 0x0055, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT3 = OBJECT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT4 = OBJECT_END + 0x0057, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT0 = OBJECT_END + 0x0058, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT1 = OBJECT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT2 = OBJECT_END + 0x005A, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT3 = OBJECT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT4 = OBJECT_END + 0x005C, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_RESISTANCES = OBJECT_END + 0x005D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE = OBJECT_END + 0x0064, // Size: 7, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE = OBJECT_END + 0x006B, // Size: 7, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_BASE_MANA = OBJECT_END + 0x0072, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_BASE_HEALTH = OBJECT_END + 0x0073, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_BYTES_2 = OBJECT_END + 0x0074, // Size: 1, Type: BYTES, Flags: PUBLIC - UNIT_FIELD_ATTACK_POWER = OBJECT_END + 0x0075, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_ATTACK_POWER_MODS = OBJECT_END + 0x0076, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER - UNIT_FIELD_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x0077, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_RANGED_ATTACK_POWER = OBJECT_END + 0x0078, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_RANGED_ATTACK_POWER_MODS = OBJECT_END + 0x0079, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER - UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x007A, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_MINRANGEDDAMAGE = OBJECT_END + 0x007B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_MAXRANGEDDAMAGE = OBJECT_END + 0x007C, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_POWER_COST_MODIFIER = OBJECT_END + 0x007D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POWER_COST_MULTIPLIER = OBJECT_END + 0x0084, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_MAXHEALTHMODIFIER = OBJECT_END + 0x008B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_HOVERHEIGHT = OBJECT_END + 0x008C, // Size: 1, Type: FLOAT, Flags: PUBLIC - UNIT_FIELD_PADDING = OBJECT_END + 0x008D, // Size: 1, Type: INT, Flags: NONE - UNIT_END = OBJECT_END + 0x008E, + UNIT_FIELD_CHARM = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_SUMMON = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_CRITTER = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PRIVATE + UNIT_FIELD_CHARMEDBY = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_SUMMONEDBY = OBJECT_END + 0x0008, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_CREATEDBY = OBJECT_END + 0x000A, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_TARGET = OBJECT_END + 0x000C, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_CHANNEL_OBJECT = OBJECT_END + 0x000E, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_CHANNEL_SPELL = OBJECT_END + 0x0010, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_BYTES_0 = OBJECT_END + 0x0011, // Size: 1, Type: BYTES, Flags: PUBLIC + UNIT_FIELD_HEALTH = OBJECT_END + 0x0012, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER1 = OBJECT_END + 0x0013, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER2 = OBJECT_END + 0x0014, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER3 = OBJECT_END + 0x0015, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER4 = OBJECT_END + 0x0016, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER5 = OBJECT_END + 0x0017, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXHEALTH = OBJECT_END + 0x0018, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER1 = OBJECT_END + 0x0019, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER2 = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER3 = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER4 = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER5 = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER = OBJECT_END + 0x001E, // Size: 5, Type: FLOAT, Flags: PRIVATE, OWNER, UNUSED2 + UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER = OBJECT_END + 0x0023, // Size: 5, Type: FLOAT, Flags: PRIVATE, OWNER, UNUSED2 + UNIT_FIELD_LEVEL = OBJECT_END + 0x0028, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_FACTIONTEMPLATE = OBJECT_END + 0x0029, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_VIRTUAL_ITEM_SLOT_ID = OBJECT_END + 0x002A, // Size: 3, Type: INT, Flags: PUBLIC + UNIT_FIELD_FLAGS = OBJECT_END + 0x002D, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_FLAGS_2 = OBJECT_END + 0x002E, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_AURASTATE = OBJECT_END + 0x002F, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_BASEATTACKTIME = OBJECT_END + 0x0030, // Size: 2, Type: INT, Flags: PUBLIC + UNIT_FIELD_RANGEDATTACKTIME = OBJECT_END + 0x0032, // Size: 1, Type: INT, Flags: PRIVATE + UNIT_FIELD_BOUNDINGRADIUS = OBJECT_END + 0x0033, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_FIELD_COMBATREACH = OBJECT_END + 0x0034, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_FIELD_DISPLAYID = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: DYNAMIC + UNIT_FIELD_NATIVEDISPLAYID = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MOUNTDISPLAYID = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MINDAMAGE = OBJECT_END + 0x0038, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, SPECIAL_INFO + UNIT_FIELD_MAXDAMAGE = OBJECT_END + 0x0039, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, SPECIAL_INFO + UNIT_FIELD_MINOFFHANDDAMAGE = OBJECT_END + 0x003A, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, SPECIAL_INFO + UNIT_FIELD_MAXOFFHANDDAMAGE = OBJECT_END + 0x003B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, SPECIAL_INFO + UNIT_FIELD_BYTES_1 = OBJECT_END + 0x003C, // Size: 1, Type: BYTES, Flags: PUBLIC + UNIT_FIELD_PETNUMBER = OBJECT_END + 0x003D, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_PET_NAME_TIMESTAMP = OBJECT_END + 0x003E, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_PETEXPERIENCE = OBJECT_END + 0x003F, // Size: 1, Type: INT, Flags: OWNER + UNIT_FIELD_PETNEXTLEVELEXP = OBJECT_END + 0x0040, // Size: 1, Type: INT, Flags: OWNER + UNIT_DYNAMIC_FLAGS = OBJECT_END + 0x0041, // Size: 1, Type: INT, Flags: DYNAMIC + UNIT_MOD_CAST_SPEED = OBJECT_END + 0x0042, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_MOD_CAST_HASTE = OBJECT_END + 0x0043, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_CREATED_BY_SPELL = OBJECT_END + 0x0044, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_NPC_FLAGS = OBJECT_END + 0x0045, // Size: 1, Type: INT, Flags: DYNAMIC + UNIT_NPC_EMOTESTATE = OBJECT_END + 0x0046, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_STAT0 = OBJECT_END + 0x0047, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_STAT1 = OBJECT_END + 0x0048, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_STAT2 = OBJECT_END + 0x0049, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_STAT3 = OBJECT_END + 0x004A, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_STAT4 = OBJECT_END + 0x004B, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT0 = OBJECT_END + 0x004C, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT1 = OBJECT_END + 0x004D, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT2 = OBJECT_END + 0x004E, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT3 = OBJECT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT4 = OBJECT_END + 0x0050, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT0 = OBJECT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT1 = OBJECT_END + 0x0052, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT2 = OBJECT_END + 0x0053, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT3 = OBJECT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT4 = OBJECT_END + 0x0055, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_RESISTANCES = OBJECT_END + 0x0056, // Size: 7, Type: INT, Flags: PRIVATE, OWNER, SPECIAL_INFO + UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE = OBJECT_END + 0x005D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE = OBJECT_END + 0x0064, // Size: 7, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_BASE_MANA = OBJECT_END + 0x006B, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_BASE_HEALTH = OBJECT_END + 0x006C, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_BYTES_2 = OBJECT_END + 0x006D, // Size: 1, Type: BYTES, Flags: PUBLIC + UNIT_FIELD_ATTACK_POWER = OBJECT_END + 0x006E, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_ATTACK_POWER_MOD_POS = OBJECT_END + 0x006F, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_ATTACK_POWER_MOD_NEG = OBJECT_END + 0x0070, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x0071, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_RANGED_ATTACK_POWER = OBJECT_END + 0x0072, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS = OBJECT_END + 0x0073, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_RANGED_ATTACK_POWER_MOD_NEG = OBJECT_END + 0x0074, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x0075, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_MINRANGEDDAMAGE = OBJECT_END + 0x0076, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_MAXRANGEDDAMAGE = OBJECT_END + 0x0077, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_POWER_COST_MODIFIER = OBJECT_END + 0x0078, // Size: 7, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POWER_COST_MULTIPLIER = OBJECT_END + 0x007F, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_MAXHEALTHMODIFIER = OBJECT_END + 0x0086, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_HOVERHEIGHT = OBJECT_END + 0x0087, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_FIELD_MAXITEMLEVEL = OBJECT_END + 0x0088, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_PADDING = OBJECT_END + 0x0089, // Size: 1, Type: INT, Flags: NONE + UNIT_END = OBJECT_END + 0x008A +}; + +enum EPlayerFields +{ + PLAYER_DUEL_ARBITER = UNIT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + PLAYER_FLAGS = UNIT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_GUILDRANK = UNIT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_GUILDDELETE_DATE = UNIT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_GUILDLEVEL = UNIT_END + 0x0005, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_BYTES = UNIT_END + 0x0006, // Size: 1, Type: BYTES, Flags: PUBLIC + PLAYER_BYTES_2 = UNIT_END + 0x0007, // Size: 1, Type: BYTES, Flags: PUBLIC + PLAYER_BYTES_3 = UNIT_END + 0x0008, // Size: 1, Type: BYTES, Flags: PUBLIC + PLAYER_DUEL_TEAM = UNIT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_GUILD_TIMESTAMP = UNIT_END + 0x000A, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_QUEST_LOG_1_1 = UNIT_END + 0x000B, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_1_2 = UNIT_END + 0x000C, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_1_3 = UNIT_END + 0x000D, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_1_4 = UNIT_END + 0x000F, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_2_1 = UNIT_END + 0x0010, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_2_2 = UNIT_END + 0x0011, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_2_3 = UNIT_END + 0x0012, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_2_5 = UNIT_END + 0x0014, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_3_1 = UNIT_END + 0x0015, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_3_2 = UNIT_END + 0x0016, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_3_3 = UNIT_END + 0x0017, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_3_5 = UNIT_END + 0x0019, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_4_1 = UNIT_END + 0x001A, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_4_2 = UNIT_END + 0x001B, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_4_3 = UNIT_END + 0x001C, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_4_5 = UNIT_END + 0x001E, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_5_1 = UNIT_END + 0x001F, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_5_2 = UNIT_END + 0x0020, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_5_3 = UNIT_END + 0x0021, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_5_5 = UNIT_END + 0x0023, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_6_1 = UNIT_END + 0x0024, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_6_2 = UNIT_END + 0x0025, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_6_3 = UNIT_END + 0x0026, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_6_5 = UNIT_END + 0x0028, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_7_1 = UNIT_END + 0x0029, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_7_2 = UNIT_END + 0x002A, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_7_3 = UNIT_END + 0x002B, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_7_5 = UNIT_END + 0x002D, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_8_1 = UNIT_END + 0x002E, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_8_2 = UNIT_END + 0x002F, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_8_3 = UNIT_END + 0x0030, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_8_5 = UNIT_END + 0x0032, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_9_1 = UNIT_END + 0x0033, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_9_2 = UNIT_END + 0x0034, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_9_3 = UNIT_END + 0x0035, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_9_5 = UNIT_END + 0x0037, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_10_1 = UNIT_END + 0x0038, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_10_2 = UNIT_END + 0x0039, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_10_3 = UNIT_END + 0x003A, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_10_5 = UNIT_END + 0x003C, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_11_1 = UNIT_END + 0x003D, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_11_2 = UNIT_END + 0x003E, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_11_3 = UNIT_END + 0x003F, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_11_5 = UNIT_END + 0x0041, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_12_1 = UNIT_END + 0x0042, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_12_2 = UNIT_END + 0x0043, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_12_3 = UNIT_END + 0x0044, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_12_5 = UNIT_END + 0x0046, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_13_1 = UNIT_END + 0x0047, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_13_2 = UNIT_END + 0x0048, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_13_3 = UNIT_END + 0x0049, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_13_5 = UNIT_END + 0x004B, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_14_1 = UNIT_END + 0x004C, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_14_2 = UNIT_END + 0x004D, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_14_3 = UNIT_END + 0x004E, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_14_5 = UNIT_END + 0x0050, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_15_1 = UNIT_END + 0x0051, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_15_2 = UNIT_END + 0x0052, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_15_3 = UNIT_END + 0x0053, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_15_5 = UNIT_END + 0x0055, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_16_1 = UNIT_END + 0x0056, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_16_2 = UNIT_END + 0x0057, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_16_3 = UNIT_END + 0x0058, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_16_5 = UNIT_END + 0x005A, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_17_1 = UNIT_END + 0x005B, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_17_2 = UNIT_END + 0x005C, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_17_3 = UNIT_END + 0x005D, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_17_5 = UNIT_END + 0x005F, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_18_1 = UNIT_END + 0x0060, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_18_2 = UNIT_END + 0x0061, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_18_3 = UNIT_END + 0x0062, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_18_5 = UNIT_END + 0x0064, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_19_1 = UNIT_END + 0x0065, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_19_2 = UNIT_END + 0x0066, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_19_3 = UNIT_END + 0x0067, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_19_5 = UNIT_END + 0x0069, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_20_1 = UNIT_END + 0x006A, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_20_2 = UNIT_END + 0x006B, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_20_3 = UNIT_END + 0x006C, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_20_5 = UNIT_END + 0x006E, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_21_1 = UNIT_END + 0x006F, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_21_2 = UNIT_END + 0x0070, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_21_3 = UNIT_END + 0x0071, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_21_5 = UNIT_END + 0x0073, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_22_1 = UNIT_END + 0x0074, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_22_2 = UNIT_END + 0x0075, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_22_3 = UNIT_END + 0x0076, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_22_5 = UNIT_END + 0x0078, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_23_1 = UNIT_END + 0x0079, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_23_2 = UNIT_END + 0x007A, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_23_3 = UNIT_END + 0x007B, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_23_5 = UNIT_END + 0x007D, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_24_1 = UNIT_END + 0x007E, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_24_2 = UNIT_END + 0x007F, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_24_3 = UNIT_END + 0x0080, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_24_5 = UNIT_END + 0x0082, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_25_1 = UNIT_END + 0x0083, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_25_2 = UNIT_END + 0x0084, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_25_3 = UNIT_END + 0x0085, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_25_5 = UNIT_END + 0x0087, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_26_1 = UNIT_END + 0x0088, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_26_2 = UNIT_END + 0x0089, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_26_3 = UNIT_END + 0x008A, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_26_5 = UNIT_END + 0x008C, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_27_1 = UNIT_END + 0x008D, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_27_2 = UNIT_END + 0x008E, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_27_3 = UNIT_END + 0x008F, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_27_5 = UNIT_END + 0x0091, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_28_1 = UNIT_END + 0x0092, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_28_2 = UNIT_END + 0x0093, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_28_3 = UNIT_END + 0x0094, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_28_5 = UNIT_END + 0x0096, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_29_1 = UNIT_END + 0x0097, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_29_2 = UNIT_END + 0x0098, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_29_3 = UNIT_END + 0x0099, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_29_5 = UNIT_END + 0x009B, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_30_1 = UNIT_END + 0x009C, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_30_2 = UNIT_END + 0x009D, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_30_3 = UNIT_END + 0x009E, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_30_5 = UNIT_END + 0x00A0, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_31_1 = UNIT_END + 0x00A1, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_31_2 = UNIT_END + 0x00A2, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_31_3 = UNIT_END + 0x00A3, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_31_5 = UNIT_END + 0x00A5, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_32_1 = UNIT_END + 0x00A6, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_32_2 = UNIT_END + 0x00A7, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_32_3 = UNIT_END + 0x00A8, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_32_5 = UNIT_END + 0x00AA, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_33_1 = UNIT_END + 0x00AB, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_33_2 = UNIT_END + 0x00AC, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_33_3 = UNIT_END + 0x00AD, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_33_5 = UNIT_END + 0x00AF, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_34_1 = UNIT_END + 0x00B0, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_34_2 = UNIT_END + 0x00B1, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_34_3 = UNIT_END + 0x00B2, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_34_5 = UNIT_END + 0x00B4, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_35_1 = UNIT_END + 0x00B5, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_35_2 = UNIT_END + 0x00B6, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_35_3 = UNIT_END + 0x00B7, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_35_5 = UNIT_END + 0x00B9, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_36_1 = UNIT_END + 0x00BA, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_36_2 = UNIT_END + 0x00BB, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_36_3 = UNIT_END + 0x00BC, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_36_5 = UNIT_END + 0x00BE, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_37_1 = UNIT_END + 0x00BF, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_37_2 = UNIT_END + 0x00C0, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_37_3 = UNIT_END + 0x00C1, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_37_5 = UNIT_END + 0x00C3, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_38_1 = UNIT_END + 0x00C4, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_38_2 = UNIT_END + 0x00C5, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_38_3 = UNIT_END + 0x00C6, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_38_5 = UNIT_END + 0x00C8, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_39_1 = UNIT_END + 0x00C9, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_39_2 = UNIT_END + 0x00CA, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_39_3 = UNIT_END + 0x00CB, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_39_5 = UNIT_END + 0x00CD, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_40_1 = UNIT_END + 0x00CE, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_40_2 = UNIT_END + 0x00CF, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_40_3 = UNIT_END + 0x00D0, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_40_5 = UNIT_END + 0x00D2, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_41_1 = UNIT_END + 0x00D3, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_41_2 = UNIT_END + 0x00D4, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_41_3 = UNIT_END + 0x00D5, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_41_5 = UNIT_END + 0x00D7, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_42_1 = UNIT_END + 0x00D8, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_42_2 = UNIT_END + 0x00D9, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_42_3 = UNIT_END + 0x00DA, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_42_5 = UNIT_END + 0x00DC, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_43_1 = UNIT_END + 0x00DD, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_43_2 = UNIT_END + 0x00DE, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_43_3 = UNIT_END + 0x00DF, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_43_5 = UNIT_END + 0x00E1, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_44_1 = UNIT_END + 0x00E2, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_44_2 = UNIT_END + 0x00E3, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_44_3 = UNIT_END + 0x00E4, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_44_5 = UNIT_END + 0x00E6, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_45_1 = UNIT_END + 0x00E7, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_45_2 = UNIT_END + 0x00E8, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_45_3 = UNIT_END + 0x00E9, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_45_5 = UNIT_END + 0x00EB, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_46_1 = UNIT_END + 0x00EC, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_46_2 = UNIT_END + 0x00ED, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_46_3 = UNIT_END + 0x00EE, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_46_5 = UNIT_END + 0x00F0, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_47_1 = UNIT_END + 0x00F1, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_47_2 = UNIT_END + 0x00F2, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_47_3 = UNIT_END + 0x00F3, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_47_5 = UNIT_END + 0x00F5, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_48_1 = UNIT_END + 0x00F6, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_48_2 = UNIT_END + 0x00F7, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_48_3 = UNIT_END + 0x00F8, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_48_5 = UNIT_END + 0x00FA, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_49_1 = UNIT_END + 0x00FB, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_49_2 = UNIT_END + 0x00FC, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_49_3 = UNIT_END + 0x00FD, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_49_5 = UNIT_END + 0x00FF, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_50_1 = UNIT_END + 0x0100, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_50_2 = UNIT_END + 0x0101, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_50_3 = UNIT_END + 0x0102, // Size: 2, Type: TWO_SHORT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_50_5 = UNIT_END + 0x0104, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_VISIBLE_ITEM_1_ENTRYID = UNIT_END + 0x0105, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_1_ENCHANTMENT = UNIT_END + 0x0106, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_2_ENTRYID = UNIT_END + 0x0107, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_2_ENCHANTMENT = UNIT_END + 0x0108, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_3_ENTRYID = UNIT_END + 0x0109, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_3_ENCHANTMENT = UNIT_END + 0x010A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_4_ENTRYID = UNIT_END + 0x010B, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_4_ENCHANTMENT = UNIT_END + 0x010C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_5_ENTRYID = UNIT_END + 0x010D, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_5_ENCHANTMENT = UNIT_END + 0x010E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_6_ENTRYID = UNIT_END + 0x010F, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_6_ENCHANTMENT = UNIT_END + 0x0110, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_7_ENTRYID = UNIT_END + 0x0111, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_7_ENCHANTMENT = UNIT_END + 0x0112, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_8_ENTRYID = UNIT_END + 0x0113, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_8_ENCHANTMENT = UNIT_END + 0x0114, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_9_ENTRYID = UNIT_END + 0x0115, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_9_ENCHANTMENT = UNIT_END + 0x0116, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_10_ENTRYID = UNIT_END + 0x0117, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_10_ENCHANTMENT = UNIT_END + 0x0118, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_11_ENTRYID = UNIT_END + 0x0119, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_11_ENCHANTMENT = UNIT_END + 0x011A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_12_ENTRYID = UNIT_END + 0x011B, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_12_ENCHANTMENT = UNIT_END + 0x011C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_13_ENTRYID = UNIT_END + 0x011D, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_13_ENCHANTMENT = UNIT_END + 0x011E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_14_ENTRYID = UNIT_END + 0x011F, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_14_ENCHANTMENT = UNIT_END + 0x0120, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_15_ENTRYID = UNIT_END + 0x0121, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_15_ENCHANTMENT = UNIT_END + 0x0122, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_16_ENTRYID = UNIT_END + 0x0123, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_16_ENCHANTMENT = UNIT_END + 0x0124, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_17_ENTRYID = UNIT_END + 0x0125, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_17_ENCHANTMENT = UNIT_END + 0x0126, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_18_ENTRYID = UNIT_END + 0x0127, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_18_ENCHANTMENT = UNIT_END + 0x0128, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_19_ENTRYID = UNIT_END + 0x0129, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_19_ENCHANTMENT = UNIT_END + 0x012A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_CHOSEN_TITLE = UNIT_END + 0x012B, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_FAKE_INEBRIATION = UNIT_END + 0x012C, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_FIELD_PAD_0 = UNIT_END + 0x012D, // Size: 1, Type: INT, Flags: NONE + PLAYER_END_NOT_SELF = UNIT_END + 0x012E, - PLAYER_DUEL_ARBITER = UNIT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - PLAYER_FLAGS = UNIT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_GUILDID = UNIT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_GUILDRANK = UNIT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_BYTES = UNIT_END + 0x0005, // Size: 1, Type: BYTES, Flags: PUBLIC - PLAYER_BYTES_2 = UNIT_END + 0x0006, // Size: 1, Type: BYTES, Flags: PUBLIC - PLAYER_BYTES_3 = UNIT_END + 0x0007, // Size: 1, Type: BYTES, Flags: PUBLIC - PLAYER_DUEL_TEAM = UNIT_END + 0x0008, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_GUILD_TIMESTAMP = UNIT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_QUEST_LOG_1_1 = UNIT_END + 0x000A, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_1_2 = UNIT_END + 0x000B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_1_3 = UNIT_END + 0x000C, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_1_4 = UNIT_END + 0x000E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_2_1 = UNIT_END + 0x000F, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_2_2 = UNIT_END + 0x0010, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_2_3 = UNIT_END + 0x0011, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_2_5 = UNIT_END + 0x0013, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_3_1 = UNIT_END + 0x0014, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_3_2 = UNIT_END + 0x0015, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_3_3 = UNIT_END + 0x0016, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_3_5 = UNIT_END + 0x0018, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_4_1 = UNIT_END + 0x0019, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_4_2 = UNIT_END + 0x001A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_4_3 = UNIT_END + 0x001B, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_4_5 = UNIT_END + 0x001D, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_5_1 = UNIT_END + 0x001E, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_5_2 = UNIT_END + 0x001F, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_5_3 = UNIT_END + 0x0020, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_5_5 = UNIT_END + 0x0022, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_6_1 = UNIT_END + 0x0023, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_6_2 = UNIT_END + 0x0024, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_6_3 = UNIT_END + 0x0025, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_6_5 = UNIT_END + 0x0027, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_7_1 = UNIT_END + 0x0028, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_7_2 = UNIT_END + 0x0029, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_7_3 = UNIT_END + 0x002A, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_7_5 = UNIT_END + 0x002C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_8_1 = UNIT_END + 0x002D, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_8_2 = UNIT_END + 0x002E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_8_3 = UNIT_END + 0x002F, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_8_5 = UNIT_END + 0x0031, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_9_1 = UNIT_END + 0x0032, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_9_2 = UNIT_END + 0x0033, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_9_3 = UNIT_END + 0x0034, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_9_5 = UNIT_END + 0x0036, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_10_1 = UNIT_END + 0x0037, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_10_2 = UNIT_END + 0x0038, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_10_3 = UNIT_END + 0x0039, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_10_5 = UNIT_END + 0x003B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_11_1 = UNIT_END + 0x003C, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_11_2 = UNIT_END + 0x003D, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_11_3 = UNIT_END + 0x003E, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_11_5 = UNIT_END + 0x0040, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_12_1 = UNIT_END + 0x0041, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_12_2 = UNIT_END + 0x0042, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_12_3 = UNIT_END + 0x0043, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_12_5 = UNIT_END + 0x0045, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_13_1 = UNIT_END + 0x0046, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_13_2 = UNIT_END + 0x0047, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_13_3 = UNIT_END + 0x0048, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_13_5 = UNIT_END + 0x004A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_14_1 = UNIT_END + 0x004B, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_14_2 = UNIT_END + 0x004C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_14_3 = UNIT_END + 0x004D, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_14_5 = UNIT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_15_1 = UNIT_END + 0x0050, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_15_2 = UNIT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_15_3 = UNIT_END + 0x0052, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_15_5 = UNIT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_16_1 = UNIT_END + 0x0055, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_16_2 = UNIT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_16_3 = UNIT_END + 0x0057, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_16_5 = UNIT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_17_1 = UNIT_END + 0x005A, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_17_2 = UNIT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_17_3 = UNIT_END + 0x005C, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_17_5 = UNIT_END + 0x005E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_18_1 = UNIT_END + 0x005F, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_18_2 = UNIT_END + 0x0060, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_18_3 = UNIT_END + 0x0061, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_18_5 = UNIT_END + 0x0063, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_19_1 = UNIT_END + 0x0064, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_19_2 = UNIT_END + 0x0065, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_19_3 = UNIT_END + 0x0066, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_19_5 = UNIT_END + 0x0068, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_20_1 = UNIT_END + 0x0069, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_20_2 = UNIT_END + 0x006A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_20_3 = UNIT_END + 0x006B, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_20_5 = UNIT_END + 0x006D, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_21_1 = UNIT_END + 0x006E, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_21_2 = UNIT_END + 0x006F, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_21_3 = UNIT_END + 0x0070, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_21_5 = UNIT_END + 0x0072, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_22_1 = UNIT_END + 0x0073, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_22_2 = UNIT_END + 0x0074, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_22_3 = UNIT_END + 0x0075, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_22_5 = UNIT_END + 0x0077, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_23_1 = UNIT_END + 0x0078, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_23_2 = UNIT_END + 0x0079, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_23_3 = UNIT_END + 0x007A, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_23_5 = UNIT_END + 0x007C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_24_1 = UNIT_END + 0x007D, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_24_2 = UNIT_END + 0x007E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_24_3 = UNIT_END + 0x007F, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_24_5 = UNIT_END + 0x0081, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_25_1 = UNIT_END + 0x0082, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_25_2 = UNIT_END + 0x0083, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_25_3 = UNIT_END + 0x0084, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_25_5 = UNIT_END + 0x0086, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_VISIBLE_ITEM_1_ENTRYID = UNIT_END + 0x0087, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_1_ENCHANTMENT = UNIT_END + 0x0088, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_2_ENTRYID = UNIT_END + 0x0089, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_2_ENCHANTMENT = UNIT_END + 0x008A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_3_ENTRYID = UNIT_END + 0x008B, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_3_ENCHANTMENT = UNIT_END + 0x008C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_4_ENTRYID = UNIT_END + 0x008D, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_4_ENCHANTMENT = UNIT_END + 0x008E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_5_ENTRYID = UNIT_END + 0x008F, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_5_ENCHANTMENT = UNIT_END + 0x0090, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_6_ENTRYID = UNIT_END + 0x0091, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_6_ENCHANTMENT = UNIT_END + 0x0092, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_7_ENTRYID = UNIT_END + 0x0093, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_7_ENCHANTMENT = UNIT_END + 0x0094, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_8_ENTRYID = UNIT_END + 0x0095, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_8_ENCHANTMENT = UNIT_END + 0x0096, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_9_ENTRYID = UNIT_END + 0x0097, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_9_ENCHANTMENT = UNIT_END + 0x0098, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_10_ENTRYID = UNIT_END + 0x0099, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_10_ENCHANTMENT = UNIT_END + 0x009A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_11_ENTRYID = UNIT_END + 0x009B, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_11_ENCHANTMENT = UNIT_END + 0x009C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_12_ENTRYID = UNIT_END + 0x009D, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_12_ENCHANTMENT = UNIT_END + 0x009E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_13_ENTRYID = UNIT_END + 0x009F, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_13_ENCHANTMENT = UNIT_END + 0x00A0, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_14_ENTRYID = UNIT_END + 0x00A1, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_14_ENCHANTMENT = UNIT_END + 0x00A2, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_15_ENTRYID = UNIT_END + 0x00A3, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_15_ENCHANTMENT = UNIT_END + 0x00A4, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_16_ENTRYID = UNIT_END + 0x00A5, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_16_ENCHANTMENT = UNIT_END + 0x00A6, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_17_ENTRYID = UNIT_END + 0x00A7, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_17_ENCHANTMENT = UNIT_END + 0x00A8, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_18_ENTRYID = UNIT_END + 0x00A9, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_18_ENCHANTMENT = UNIT_END + 0x00AA, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_19_ENTRYID = UNIT_END + 0x00AB, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_19_ENCHANTMENT = UNIT_END + 0x00AC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_CHOSEN_TITLE = UNIT_END + 0x00AD, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_FAKE_INEBRIATION = UNIT_END + 0x00AE, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_FIELD_PAD_0 = UNIT_END + 0x00AF, // Size: 1, Type: INT, Flags: NONE - PLAYER_FIELD_INV_SLOT_HEAD = UNIT_END + 0x00B0, // Size: 46, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_PACK_SLOT_1 = UNIT_END + 0x00DE, // Size: 32, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_BANK_SLOT_1 = UNIT_END + 0x00FE, // Size: 56, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_BANKBAG_SLOT_1 = UNIT_END + 0x0136, // Size: 14, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_VENDORBUYBACK_SLOT_1 = UNIT_END + 0x0144, // Size: 24, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_KEYRING_SLOT_1 = UNIT_END + 0x015C, // Size: 64, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_CURRENCYTOKEN_SLOT_1 = UNIT_END + 0x019C, // Size: 64, Type: LONG, Flags: PRIVATE - PLAYER_FARSIGHT = UNIT_END + 0x01DC, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER__FIELD_KNOWN_TITLES = UNIT_END + 0x01DE, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER__FIELD_KNOWN_TITLES1 = UNIT_END + 0x01E0, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER__FIELD_KNOWN_TITLES2 = UNIT_END + 0x01E2, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_KNOWN_CURRENCIES = UNIT_END + 0x01E4, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER_XP = UNIT_END + 0x01E6, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_NEXT_LEVEL_XP = UNIT_END + 0x01E7, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_SKILL_INFO_1_1 = UNIT_END + 0x01E8, // Size: 384, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_CHARACTER_POINTS1 = UNIT_END + 0x0368, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_CHARACTER_POINTS2 = UNIT_END + 0x0369, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_TRACK_CREATURES = UNIT_END + 0x036A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_TRACK_RESOURCES = UNIT_END + 0x036B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_BLOCK_PERCENTAGE = UNIT_END + 0x036C, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_DODGE_PERCENTAGE = UNIT_END + 0x036D, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_PARRY_PERCENTAGE = UNIT_END + 0x036E, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_EXPERTISE = UNIT_END + 0x036F, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_OFFHAND_EXPERTISE = UNIT_END + 0x0370, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_CRIT_PERCENTAGE = UNIT_END + 0x0371, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_RANGED_CRIT_PERCENTAGE = UNIT_END + 0x0372, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_OFFHAND_CRIT_PERCENTAGE = UNIT_END + 0x0373, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_SPELL_CRIT_PERCENTAGE1 = UNIT_END + 0x0374, // Size: 7, Type: FLOAT, Flags: PRIVATE - PLAYER_SHIELD_BLOCK = UNIT_END + 0x037B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_SHIELD_BLOCK_CRIT_PERCENTAGE = UNIT_END + 0x037C, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_EXPLORED_ZONES_1 = UNIT_END + 0x037D, // Size: 128, Type: BYTES, Flags: PRIVATE - PLAYER_REST_STATE_EXPERIENCE = UNIT_END + 0x03FD, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_COINAGE = UNIT_END + 0x03FE, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_DAMAGE_DONE_POS = UNIT_END + 0x03FF, // Size: 7, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_DAMAGE_DONE_NEG = UNIT_END + 0x0406, // Size: 7, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_DAMAGE_DONE_PCT = UNIT_END + 0x040D, // Size: 7, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_HEALING_DONE_POS = UNIT_END + 0x0414, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_HEALING_PCT = UNIT_END + 0x0415, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_FIELD_MOD_HEALING_DONE_PCT = UNIT_END + 0x0416, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x0417, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x0418, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BYTES = UNIT_END + 0x0419, // Size: 1, Type: BYTES, Flags: PRIVATE - PLAYER_AMMO_ID = UNIT_END + 0x041A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_SELF_RES_SPELL = UNIT_END + 0x041B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x041C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x041D, // Size: 12, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x0429, // Size: 12, Type: INT, Flags: PRIVATE - PLAYER_FIELD_KILLS = UNIT_END + 0x0435, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_FIELD_TODAY_CONTRIBUTION = UNIT_END + 0x0436, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_YESTERDAY_CONTRIBUTION = UNIT_END + 0x0437, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_LIFETIME_HONORABLE_KILLS = UNIT_END + 0x0438, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BYTES2 = UNIT_END + 0x0439, // Size: 1, Type: 6, Flags: PRIVATE - PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x043A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x043B, // Size: 25, Type: INT, Flags: PRIVATE - PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x0454, // Size: 21, Type: INT, Flags: PRIVATE - PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x0469, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x046A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x046B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x046C, // Size: 25, Type: INT, Flags: PRIVATE - PLAYER_RUNE_REGEN_1 = UNIT_END + 0x0485, // Size: 4, Type: FLOAT, Flags: PRIVATE - PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x0489, // Size: 3, Type: INT, Flags: PRIVATE - PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x048C, // Size: 6, Type: INT, Flags: PRIVATE - PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x0492, // Size: 6, Type: INT, Flags: PRIVATE - PLAYER_GLYPHS_ENABLED = UNIT_END + 0x0498, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_PET_SPELL_POWER = UNIT_END + 0x0499, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_END = UNIT_END + 0x049A + PLAYER_FIELD_INV_SLOT_HEAD = UNIT_END + 0x012E, // Size: 46, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_PACK_SLOT_1 = UNIT_END + 0x015C, // Size: 32, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_BANK_SLOT_1 = UNIT_END + 0x017C, // Size: 56, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_BANKBAG_SLOT_1 = UNIT_END + 0x01B4, // Size: 14, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_VENDORBUYBACK_SLOT_1 = UNIT_END + 0x01C2, // Size: 24, Type: LONG, Flags: PRIVATE + PLAYER_FARSIGHT = UNIT_END + 0x01DA, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER__FIELD_KNOWN_TITLES = UNIT_END + 0x01DC, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER__FIELD_KNOWN_TITLES1 = UNIT_END + 0x01DE, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER__FIELD_KNOWN_TITLES2 = UNIT_END + 0x01E0, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER__FIELD_KNOWN_TITLES3 = UNIT_END + 0x01E2, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER_XP = UNIT_END + 0x01E4, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_NEXT_LEVEL_XP = UNIT_END + 0x01E5, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_SKILL_LINEID_0 = UNIT_END + 0x01E6, // Size: 64, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_SKILL_STEP_0 = UNIT_END + 0x0226, // Size: 64, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_SKILL_RANK_0 = UNIT_END + 0x0266, // Size: 64, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_SKILL_MAX_RANK_0 = UNIT_END + 0x02A6, // Size: 64, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_SKILL_MODIFIER_0 = UNIT_END + 0x02E6, // Size: 64, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_SKILL_TALENT_0 = UNIT_END + 0x0326, // Size: 64, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_CHARACTER_POINTS = UNIT_END + 0x0366, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_TRACK_CREATURES = UNIT_END + 0x0367, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_TRACK_RESOURCES = UNIT_END + 0x0368, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_EXPERTISE = UNIT_END + 0x0369, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_OFFHAND_EXPERTISE = UNIT_END + 0x036A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_BLOCK_PERCENTAGE = UNIT_END + 0x036B, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_DODGE_PERCENTAGE = UNIT_END + 0x036C, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_PARRY_PERCENTAGE = UNIT_END + 0x036D, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_CRIT_PERCENTAGE = UNIT_END + 0x036E, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_RANGED_CRIT_PERCENTAGE = UNIT_END + 0x036F, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_OFFHAND_CRIT_PERCENTAGE = UNIT_END + 0x0370, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_SPELL_CRIT_PERCENTAGE1 = UNIT_END + 0x0371, // Size: 7, Type: FLOAT, Flags: PRIVATE + PLAYER_SHIELD_BLOCK = UNIT_END + 0x0378, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_SHIELD_BLOCK_CRIT_PERCENTAGE = UNIT_END + 0x0379, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_MASTERY = UNIT_END + 0x037A, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_EXPLORED_ZONES_1 = UNIT_END + 0x037B, // Size: 156, Type: BYTES, Flags: PRIVATE + PLAYER_REST_STATE_EXPERIENCE = UNIT_END + 0x0417, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_COINAGE = UNIT_END + 0x0418, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_MOD_DAMAGE_DONE_POS = UNIT_END + 0x041A, // Size: 7, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_DAMAGE_DONE_NEG = UNIT_END + 0x0421, // Size: 7, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_DAMAGE_DONE_PCT = UNIT_END + 0x0428, // Size: 7, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_HEALING_DONE_POS = UNIT_END + 0x042F, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_HEALING_PCT = UNIT_END + 0x0430, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_HEALING_DONE_PCT = UNIT_END + 0x0431, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_WEAPON_DMG_MULTIPLIERS = UNIT_END + 0x0432, // Size: 3, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_SPELL_POWER_PCT = UNIT_END + 0x0435, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_OVERRIDE_SPELL_POWER_BY_AP_PCT = UNIT_END + 0x0436, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x0437, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x0438, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BYTES = UNIT_END + 0x0439, // Size: 1, Type: BYTES, Flags: PRIVATE + PLAYER_SELF_RES_SPELL = UNIT_END + 0x043A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x043B, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x043C, // Size: 12, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x0448, // Size: 12, Type: INT, Flags: PRIVATE + PLAYER_FIELD_KILLS = UNIT_END + 0x0454, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_FIELD_LIFETIME_HONORABLE_KILLS = UNIT_END + 0x0455, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BYTES2 = UNIT_END + 0x0456, // Size: 1, Type: 6, Flags: PRIVATE + PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x0457, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x0458, // Size: 26, Type: INT, Flags: PRIVATE + PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x0472, // Size: 21, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BATTLEGROUND_RATING = UNIT_END + 0x0487, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x0488, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x0489, // Size: 25, Type: INT, Flags: PRIVATE + PLAYER_RUNE_REGEN_1 = UNIT_END + 0x04A2, // Size: 4, Type: FLOAT, Flags: PRIVATE + PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x04A6, // Size: 3, Type: INT, Flags: PRIVATE + PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x04A9, // Size: 9, Type: INT, Flags: PRIVATE + PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x04B2, // Size: 9, Type: INT, Flags: PRIVATE + PLAYER_GLYPHS_ENABLED = UNIT_END + 0x04BB, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_PET_SPELL_POWER = UNIT_END + 0x04BC, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_RESEARCHING_1 = UNIT_END + 0x04BD, // Size: 8, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_FIELD_RESERACH_SITE_1 = UNIT_END + 0x04C5, // Size: 8, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_PROFESSION_SKILL_LINE_1 = UNIT_END + 0x04CD, // Size: 2, Type: INT, Flags: PRIVATE + PLAYER_FIELD_UI_HIT_MODIFIER = UNIT_END + 0x04CF, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_UI_SPELL_HIT_MODIFIER = UNIT_END + 0x04D0, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_HOME_REALM_TIME_OFFSET = UNIT_END + 0x04D1, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_HASTE = UNIT_END + 0x04D2, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_RANGED_HASTE = UNIT_END + 0x04D3, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_PET_HASTE = UNIT_END + 0x04D4, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_HASTE_REGEN = UNIT_END + 0x04D5, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_END = UNIT_END + 0x04D6 }; enum EGameObjectFields { - OBJECT_FIELD_CREATED_BY = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - GAMEOBJECT_DISPLAYID = OBJECT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC - GAMEOBJECT_FLAGS = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC - GAMEOBJECT_PARENTROTATION = OBJECT_END + 0x0004, // Size: 4, Type: FLOAT, Flags: PUBLIC - GAMEOBJECT_DYNAMIC = OBJECT_END + 0x0008, // Size: 1, Type: TWO_SHORT, Flags: DYNAMIC - GAMEOBJECT_FACTION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC - GAMEOBJECT_LEVEL = OBJECT_END + 0x000A, // Size: 1, Type: INT, Flags: PUBLIC - GAMEOBJECT_BYTES_1 = OBJECT_END + 0x000B, // Size: 1, Type: BYTES, Flags: PUBLIC - GAMEOBJECT_END = OBJECT_END + 0x000C + OBJECT_FIELD_CREATED_BY = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + GAMEOBJECT_DISPLAYID = OBJECT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC + GAMEOBJECT_FLAGS = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC + GAMEOBJECT_PARENTROTATION = OBJECT_END + 0x0004, // Size: 4, Type: FLOAT, Flags: PUBLIC + GAMEOBJECT_DYNAMIC = OBJECT_END + 0x0008, // Size: 1, Type: TWO_SHORT, Flags: DYNAMIC + GAMEOBJECT_FACTION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC + GAMEOBJECT_LEVEL = OBJECT_END + 0x000A, // Size: 1, Type: INT, Flags: PUBLIC + GAMEOBJECT_BYTES_1 = OBJECT_END + 0x000B, // Size: 1, Type: BYTES, Flags: PUBLIC + GAMEOBJECT_END = OBJECT_END + 0x000C }; enum EDynamicObjectFields { - DYNAMICOBJECT_CASTER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - DYNAMICOBJECT_BYTES = OBJECT_END + 0x0002, // Size: 1, Type: BYTES, Flags: PUBLIC - DYNAMICOBJECT_SPELLID = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC - DYNAMICOBJECT_RADIUS = OBJECT_END + 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC - DYNAMICOBJECT_CASTTIME = OBJECT_END + 0x0005, // Size: 1, Type: INT, Flags: PUBLIC - DYNAMICOBJECT_END = OBJECT_END + 0x0006 + DYNAMICOBJECT_CASTER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + DYNAMICOBJECT_BYTES = OBJECT_END + 0x0002, // Size: 1, Type: INT, Flags: DYNAMIC + DYNAMICOBJECT_SPELLID = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC + DYNAMICOBJECT_RADIUS = OBJECT_END + 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC + DYNAMICOBJECT_CASTTIME = OBJECT_END + 0x0005, // Size: 1, Type: INT, Flags: PUBLIC + DYNAMICOBJECT_END = OBJECT_END + 0x0006 }; enum ECorpseFields { - CORPSE_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - CORPSE_FIELD_PARTY = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC - CORPSE_FIELD_DISPLAY_ID = OBJECT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC - CORPSE_FIELD_ITEM = OBJECT_END + 0x0005, // Size: 19, Type: INT, Flags: PUBLIC - CORPSE_FIELD_BYTES_1 = OBJECT_END + 0x0018, // Size: 1, Type: BYTES, Flags: PUBLIC - CORPSE_FIELD_BYTES_2 = OBJECT_END + 0x0019, // Size: 1, Type: BYTES, Flags: PUBLIC - CORPSE_FIELD_GUILD = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC - CORPSE_FIELD_FLAGS = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC - CORPSE_FIELD_DYNAMIC_FLAGS = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: DYNAMIC - CORPSE_FIELD_PAD = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: NONE - CORPSE_END = OBJECT_END + 0x001E + CORPSE_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + CORPSE_FIELD_PARTY = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC + CORPSE_FIELD_DISPLAY_ID = OBJECT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC + CORPSE_FIELD_ITEM = OBJECT_END + 0x0005, // Size: 19, Type: INT, Flags: PUBLIC + CORPSE_FIELD_BYTES_1 = OBJECT_END + 0x0018, // Size: 1, Type: BYTES, Flags: PUBLIC + CORPSE_FIELD_BYTES_2 = OBJECT_END + 0x0019, // Size: 1, Type: BYTES, Flags: PUBLIC + CORPSE_FIELD_FLAGS = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC + CORPSE_FIELD_DYNAMIC_FLAGS = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: DYNAMIC + CORPSE_END = OBJECT_END + 0x001C }; -#endif + +enum EAreaTriggerFields +{ + AREATRIGGER_SPELLID = OBJECT_END + 0x0000, // Size: 1, Type: INT, Flags: PUBLIC + AREATRIGGER_SPELLVISUALID = OBJECT_END + 0x0001, // Size: 1, Type: INT, Flags: PUBLIC + AREATRIGGER_DURATION = OBJECT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC + AREATRIGGER_FINAL_POS = OBJECT_END + 0x0003, // Size: 3, Type: FLOAT, Flags: PUBLIC + AREATRIGGER_END = OBJECT_END + 0x0006 +}; + +#endif // _UPDATEFIELDS_H diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 876f35a58ce..5c731c6f8f7 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -30,13 +30,14 @@ #include "Unit.h" #include "Util.h" #include "Group.h" +#include "Opcodes.h" #include "WorldSession.h" #define PET_XP_FACTOR 0.05f Pet::Pet(Player* owner, PetType type) : Guardian(NULL, owner, true), m_usedTalentCount(0), m_removed(false), - m_happinessTimer(7500), m_petType(type), m_duration(0), m_auraRaidUpdateMask(0), m_loading(false), + m_petType(type), m_duration(0), m_auraRaidUpdateMask(0), m_loading(false), m_declinedname(NULL) { ASSERT(GetOwner()); @@ -150,14 +151,14 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c if (!petEntry) return false; - uint32 summonSpellId = fields[15].GetUInt32(); + uint32 summonSpellId = fields[14].GetUInt32(); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summonSpellId); bool isTemporarySummon = spellInfo && spellInfo->GetDuration() > 0; if (current && isTemporarySummon) return false; - PetType petType = PetType(fields[16].GetUInt8()); + PetType petType = PetType(fields[15].GetUInt8()); if (petType == HUNTER_PET) { CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry); @@ -178,6 +179,9 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c if (!Create(guid, map, owner->GetPhaseMask(), petEntry, petId)) return false; + for (auto itr : owner->GetPhases()) + SetInPhase(itr, false, true); + setPetType(petType); setFaction(owner->getFaction()); SetUInt32Value(UNIT_CREATED_BY_SPELL, summonSpellId); @@ -224,8 +228,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet abandon, cancel) - SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); - SetPower(POWER_HAPPINESS, fields[12].GetUInt32()); setPowerType(POWER_FOCUS); break; default: @@ -267,7 +269,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c else { SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth); - SetPower(POWER_MANA, savedmana > GetMaxPower(POWER_MANA) ? GetMaxPower(POWER_MANA) : savedmana); + SetPower(POWER_MANA, savedmana > uint32(GetMaxPower(POWER_MANA)) ? GetMaxPower(POWER_MANA) : savedmana); } } @@ -315,13 +317,13 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c InitTalentForLevel(); // set original talents points before spell loading - uint32 timediff = uint32(time(NULL) - fields[14].GetUInt32()); + uint32 timediff = uint32(time(NULL) - fields[13].GetUInt32()); _LoadAuras(timediff); // load action bar, if data broken will fill later by default spells. if (!isTemporarySummon) { - m_charmInfo->LoadPetActionBar(fields[13].GetString()); + m_charmInfo->LoadPetActionBar(fields[12].GetString()); _LoadSpells(); InitTalentForLevel(); // re-init to check talent count @@ -447,7 +449,7 @@ void Pet::SavePetToDB(PetSaveMode mode) // save pet std::ostringstream ss; - ss << "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType) " + ss << "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType) " << "VALUES (" << m_charmInfo->GetPetNumber() << ',' << GetEntry() << ',' @@ -460,8 +462,7 @@ void Pet::SavePetToDB(PetSaveMode mode) << name.c_str() << "', " << uint32(HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1) << ',' << curhealth << ',' - << curmana << ',' - << GetPower(POWER_HAPPINESS) << ", '"; + << curmana << ", '"; for (uint32 i = ACTION_BAR_INDEX_START; i < ACTION_BAR_INDEX_END; ++i) { @@ -523,10 +524,6 @@ void Pet::setDeathState(DeathState s) // overwrite virtual SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE); RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); - // lose happiness when died and not in BG/Arena - if (!GetMap()->IsBattlegroundOrArena()) - ModifyPower(POWER_HAPPINESS, -HAPPINESS_LEVEL_SIZE); - //SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); } } @@ -620,18 +617,6 @@ void Pet::Update(uint32 diff) } } } - - if (getPetType() != HUNTER_PET) - break; - - if (m_happinessTimer <= diff) - { - LoseHappiness(); - m_happinessTimer = 7500; - } - else - m_happinessTimer -= diff; - break; } default: @@ -679,27 +664,6 @@ void Creature::Regenerate(Powers power) ModifyPower(power, int32(addvalue)); } -void Pet::LoseHappiness() -{ - uint32 curValue = GetPower(POWER_HAPPINESS); - if (curValue <= 0) - return; - int32 addvalue = 670; //value is 70/35/17/8/4 (per min) * 1000 / 8 (timer 7.5 secs) - if (IsInCombat()) //we know in combat happiness fades faster, multiplier guess - addvalue = int32(addvalue * 1.5f); - ModifyPower(POWER_HAPPINESS, -addvalue); -} - -HappinessState Pet::GetHappinessState() -{ - if (GetPower(POWER_HAPPINESS) < HAPPINESS_LEVEL_SIZE) - return UNHAPPY; - else if (GetPower(POWER_HAPPINESS) >= HAPPINESS_LEVEL_SIZE * 2) - return HAPPY; - else - return CONTENT; -} - void Pet::Remove(PetSaveMode mode, bool returnreagent) { GetOwner()->RemovePet(this, mode, returnreagent); @@ -784,7 +748,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature) SetDisplayId(creature->GetDisplayId()); if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family)) - SetName(cFamily->Name[sWorld->GetDefaultDbcLocale()]); + SetName(cFamily->Name); else SetName(creature->GetNameForLocaleIdx(sObjectMgr->GetDBCLocaleIndex())); @@ -797,7 +761,7 @@ bool Pet::CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner) return false; if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family)) - SetName(cFamily->Name[sWorld->GetDefaultDbcLocale()]); + SetName(cFamily->Name); Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation()); @@ -812,8 +776,6 @@ bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phas if (!Create(guid, map, phaseMask, cinfo->Entry, petId)) return false; - SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); - SetPower(POWER_HAPPINESS, 166500); setPowerType(POWER_FOCUS); SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0); SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); @@ -871,6 +833,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME); SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); + SetFloatValue(UNIT_MOD_CAST_HASTE, 1.0f); //scale CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family); @@ -1891,6 +1854,8 @@ bool Pet::IsPermanentPetFor(Player* owner) const return GetCreatureTemplate()->type == CREATURE_TYPE_DEMON; case CLASS_DEATH_KNIGHT: return GetCreatureTemplate()->type == CREATURE_TYPE_UNDEAD; + case CLASS_MAGE: + return GetCreatureTemplate()->type == CREATURE_TYPE_ELEMENTAL; default: return false; } diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index 68465f6b8e7..97323f3f9ab 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -77,8 +77,6 @@ class Pet : public Guardian return m_autospells[pos]; } - void LoseHappiness(); - HappinessState GetHappinessState(); void GivePetXP(uint32 xp); void GivePetLevel(uint8 level); void SynchronizeLevelWithOwner(); @@ -149,7 +147,6 @@ class Pet : public Guardian Player* GetOwner() const; protected: - uint32 m_happinessTimer; PetType m_petType; int32 m_duration; // time until unsummon (used mostly for summoned guardians and not used for controlled pets) uint64 m_auraRaidUpdateMask; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ee93fc09f5e..73d87ef4774 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -36,6 +36,7 @@ #include "ConditionMgr.h" #include "CreatureAI.h" #include "DatabaseEnv.h" +#include "DB2Stores.h" #include "DisableMgr.h" #include "Formulas.h" #include "GameEventMgr.h" @@ -78,22 +79,11 @@ #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "MovementStructures.h" #include "GameObjectAI.h" #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) -#define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3)) -#define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1) -#define PLAYER_SKILL_BONUS_INDEX(x) (PLAYER_SKILL_INDEX(x)+2) - -#define SKILL_VALUE(x) PAIR32_LOPART(x) -#define SKILL_MAX(x) PAIR32_HIPART(x) -#define MAKE_SKILL_VALUE(v, m) MAKE_PAIR32(v, m) - -#define SKILL_TEMP_BONUS(x) int16(PAIR32_LOPART(x)) -#define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x)) -#define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p) - enum CharacterFlags { CHARACTER_FLAG_NONE = 0x00000000, @@ -145,7 +135,23 @@ enum CharacterCustomizeFlags static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 }; -uint32 const MAX_MONEY_AMOUNT = static_cast<uint32>(std::numeric_limits<int32>::max()); +uint32 const MasterySpells[MAX_CLASSES] = +{ + 0, + 87500, // Warrior + 87494, // Paladin + 87493, // Hunter + 87496, // Rogue + 87495, // Priest + 87492, // Death Knight + 87497, // Shaman + 86467, // Mage + 87498, // Warlock + 0, + 87491, // Druid +}; + +uint64 const MAX_MONEY_AMOUNT = static_cast<uint64>(std::numeric_limits<int64>::max()); // == PlayerTaxi ================================================ @@ -208,15 +214,16 @@ void PlayerTaxi::LoadTaxiMask(std::string const &data) void PlayerTaxi::AppendTaximaskTo(ByteBuffer& data, bool all) { + data << uint32(TaxiMaskSize); if (all) { for (uint8 i = 0; i < TaxiMaskSize; ++i) - data << uint32(sTaxiNodesMask[i]); // all existed nodes + data << uint8(sTaxiNodesMask[i]); // all existed nodes } else { for (uint8 i = 0; i < TaxiMaskSize; ++i) - data << uint32(m_taximask[i]); // known nodes + data << uint8(m_taximask[i]); // known nodes } } @@ -284,7 +291,7 @@ uint32 PlayerTaxi::GetCurrentTaxiPath() const std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi) { for (uint8 i = 0; i < TaxiMaskSize; ++i) - ss << taxi.m_taximask[i] << ' '; + ss << uint32(taxi.m_taximask[i]) << ' '; return ss; } @@ -362,7 +369,7 @@ void TradeData::SetSpell(uint32 spell_id, Item* castItem /*= NULL*/) Update(false); // send spell info to caster self } -void TradeData::SetMoney(uint32 money) +void TradeData::SetMoney(uint64 money) { if (m_money == money) return; @@ -442,6 +449,7 @@ void TradeData::SetAccepted(bool state, bool crosssend /*= false*/) // 4.3. Give reputation (player must not be on BG). // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse). // 5. Credit instance encounter. +// 6. Update guild achievements. KillRewarder::KillRewarder(Player* killer, Unit* victim, bool isBattleGround) : // 1. Initialize internal variables to default values. _killer(killer), _victim(victim), _group(killer->GetGroup()), @@ -530,10 +538,14 @@ inline void KillRewarder::_RewardXP(Player* player, float rate) for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i) AddPct(xp, (*i)->GetAmount()); - // 4.2.3. Give XP to player. + // 4.2.3. Calculate expansion penalty + if (_victim->GetTypeId() == TYPEID_UNIT && player->getLevel() >= GetMaxLevelForExpansion(_victim->ToCreature()->GetCreatureTemplate()->expansion)) + xp = CalculatePct(xp, 10); // Players get only 10% xp for killing creatures of lower expansion levels than himself + + // 4.2.4. Give XP to player. player->GiveXP(xp, _victim, _groupRate); if (Pet* pet = player->GetPet()) - // 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case). + // 4.2.5. If player has pet, reward pet with XP (100% for single player, 50% for group case). pet->GivePetXP(_group ? xp / 2 : xp); } } @@ -552,7 +564,7 @@ inline void KillRewarder::_RewardKillCredit(Player* player) if (Creature* target = _victim->ToCreature()) { player->KilledMonster(target->GetCreatureTemplate(), target->GetGUID()); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, target->GetCreatureType(), 1, target); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, target->GetCreatureType(), 1, 0, target); } } @@ -615,7 +627,7 @@ void KillRewarder::_RewardGroup() if (member->IsAtGroupRewardDistance(_victim)) { _RewardPlayer(member, isDungeon); - member->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, _victim); + member->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, 0, _victim); } } } @@ -643,10 +655,18 @@ void KillRewarder::Reward() } // 5. Credit instance encounter. + // 6. Update guild achievements. if (Creature* victim = _victim->ToCreature()) + { if (victim->IsDungeonBoss()) if (InstanceScript* instance = _victim->GetInstanceScript()) instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, _victim->GetEntry(), _victim); + + if (uint32 guildId = victim->GetMap()->GetOwnerGuildId()) + if (Guild* guild = sGuildMgr->GetGuildById(guildId)) + guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, victim->GetEntry(), 1, 0, victim, _killer); + } + } Player::Player(WorldSession* session): Unit(true) @@ -678,11 +698,10 @@ Player::Player(WorldSession* session): Unit(true) m_comboTarget = 0; m_comboPoints = 0; - m_usedTalentCount = 0; - m_questRewardTalentCount = 0; - m_regenTimer = 0; m_regenTimerCount = 0; + m_holyPowerRegenTimerCount = 0; + m_focusRegenTimerCount = 0; m_weaponChangeTimer = 0; m_zoneUpdateId = uint32(-1); @@ -695,7 +714,7 @@ Player::Player(WorldSession* session): Unit(true) m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE); - clearResurrectRequestData(); + _resurrectionData = NULL; memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT); @@ -760,7 +779,6 @@ Player::Player(WorldSession* session): Unit(true) m_canParry = false; m_canBlock = false; m_canTitanGrip = false; - m_ammoDPS = 0.0f; m_temporaryUnsummonedPetNumber = 0; //cache for UNIT_CREATED_BY_SPELL to allow @@ -784,8 +802,6 @@ Player::Player(WorldSession* session): Unit(true) unReadMails = 0; m_nextMailDelivereTime = 0; - m_resetTalentsCost = 0; - m_resetTalentsTime = 0; m_itemUpdateQueueBlocked = false; for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) @@ -802,17 +818,7 @@ Player::Player(WorldSession* session): Unit(true) m_raidMapDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; m_lastPotionId = 0; - - m_activeSpec = 0; - m_specsCount = 1; - - for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) - { - for (uint8 g = 0; g < MAX_GLYPH_SLOT_INDEX; ++g) - m_Glyphs[i][g] = 0; - - m_talents[i] = new PlayerTalentMap(); - } + _talentMgr = new PlayerTalentInfo(); for (uint8 i = 0; i < BASEMOD_END; ++i) { @@ -824,7 +830,6 @@ Player::Player(WorldSession* session): Unit(true) m_baseRatingValue[i] = 0; m_baseSpellPower = 0; - m_baseFeralAP = 0; m_baseManaRegen = 0; m_baseHealthRegen = 0; m_spellPenetrationItemMod = 0; @@ -876,12 +881,11 @@ Player::Player(WorldSession* session): Unit(true) m_ChampioningFaction = 0; - m_timeSyncCounter = 0; m_timeSyncTimer = 0; m_timeSyncClient = 0; m_timeSyncServer = 0; - for (uint8 i = 0; i < MAX_POWERS; ++i) + for (uint8 i = 0; i < MAX_POWERS_PER_CLASS; ++i) m_powerFraction[i] = 0; isDebugAreaTriggers = false; @@ -895,7 +899,12 @@ Player::Player(WorldSession* session): Unit(true) SetPendingBind(0, 0); _activeCheats = CHEAT_NONE; - m_achievementMgr = new AchievementMgr(this); + _maxPersonalArenaRate = 0; + + memset(_voidStorageItems, 0, VOID_STORAGE_MAX_SLOT * sizeof(VoidStorageItem*)); + memset(_CUFProfiles, 0, MAX_CUF_PROFILES * sizeof(CUFProfile*)); + + m_achievementMgr = new AchievementMgr<Player>(this); m_reputationMgr = new ReputationMgr(this); } @@ -911,12 +920,7 @@ Player::~Player() for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) delete itr->second; - for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) - { - for (PlayerTalentMap::const_iterator itr = m_talents[i]->begin(); itr != m_talents[i]->end(); ++itr) - delete itr->second; - delete m_talents[i]; - } + delete _talentMgr; //all mailed items should be deleted, also all mail should be deallocated for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) @@ -935,6 +939,14 @@ Player::~Player() delete m_achievementMgr; delete m_reputationMgr; + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + delete _voidStorageItems[i]; + + for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) + delete _CUFProfiles[i]; + + ClearResurrectRequestData(); + sWorld->DecreasePlayerCount(); } @@ -1007,8 +1019,8 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); } + SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER); - SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); // fix cast time showed in spell tooltip on client SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); // default for players in 3.0.3 SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); // -1 is default value @@ -1021,8 +1033,9 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) SetByteValue(PLAYER_BYTES_3, 0, createInfo->Gender); SetByteValue(PLAYER_BYTES_3, 3, 0); // BattlefieldArenaFaction (0 or 1) - SetUInt32Value(PLAYER_GUILDID, 0); + SetUInt64Value(OBJECT_FIELD_DATA, 0); SetUInt32Value(PLAYER_GUILDRANK, 0); + SetGuildLevel(0); SetUInt32Value(PLAYER_GUILD_TIMESTAMP, 0); for (int i = 0; i < KNOWN_TITLES_SIZE; ++i) @@ -1031,8 +1044,6 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) SetUInt32Value(PLAYER_FIELD_KILLS, 0); SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0); - SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); - SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); // set starting level uint32 start_level = getClass() != CLASS_DEATH_KNIGHT @@ -1051,8 +1062,9 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) InitRunes(); SetUInt32Value(PLAYER_FIELD_COINAGE, sWorld->getIntConfig(CONFIG_START_PLAYER_MONEY)); - SetHonorPoints(sWorld->getIntConfig(CONFIG_START_HONOR_POINTS)); - SetArenaPoints(sWorld->getIntConfig(CONFIG_START_ARENA_POINTS)); + SetCurrency(CURRENCY_TYPE_HONOR_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_HONOR_POINTS)); + SetCurrency(CURRENCY_TYPE_JUSTICE_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_JUSTICE_POINTS)); + SetCurrency(CURRENCY_TYPE_CONQUEST_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_CONQUEST_POINTS)); // start with every map explored if (sWorld->getBoolConfig(CONFIG_START_ALL_EXPLORED)) @@ -1127,8 +1139,8 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) if (getPowerType() == POWER_RUNIC_POWER) { - SetPower(POWER_RUNE, 8); - SetMaxPower(POWER_RUNE, 8); + SetPower(POWER_RUNES, 8); + SetMaxPower(POWER_RUNES, 8); SetPower(POWER_RUNIC_POWER, 0); SetMaxPower(POWER_RUNIC_POWER, 1000); } @@ -1160,7 +1172,7 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) uint32 count = iProto->BuyCount; // special amount for food/drink - if (iProto->Class == ITEM_CLASS_CONSUMABLE && iProto->SubClass == ITEM_SUBCLASS_FOOD) + if (iProto->Class == ITEM_CLASS_CONSUMABLE && iProto->SubClass == ITEM_SUBCLASS_FOOD_DRINK) { switch (iProto->Spells[0].SpellCategory) { @@ -1196,7 +1208,7 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) RemoveItem(INVENTORY_SLOT_BAG_0, i, true); EquipItem(eDest, pItem, true); } - // move other items to more appropriate slots (ammo not equipped in special bag) + // move other items to more appropriate slots else { ItemPosCountVec sDest; @@ -1206,11 +1218,6 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) RemoveItem(INVENTORY_SLOT_BAG_0, i, true); pItem = StoreItem(sDest, pItem, true); } - - // if this is ammo then use it - msg = CanUseAmmo(pItem->GetEntry()); - if (msg == EQUIP_ERR_OK) - SetAmmo(pItem->GetEntry()); } } } @@ -1320,8 +1327,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) TC_LOG_DEBUG("entities.player", "We are fall to death, loosing 10 percents durability"); DurabilityLossAll(0.10f, false); // durability lost message - WorldPacket data2(SMSG_DURABILITY_DAMAGE_DEATH, 0); - GetSession()->SendPacket(&data2); + SendDurabilityLoss(this, 10); } UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM, 1, type); @@ -1876,7 +1882,7 @@ void Player::setDeathState(DeathState s) // lost combo points at any target (targeted combo points clear in Unit::setDeathState) ClearComboPoints(); - clearResurrectRequestData(); + ClearResurrectRequestData(); //FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequestOpcode and define pet unsummon here with (s == DEAD) RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); @@ -1915,100 +1921,70 @@ void Player::InnEnter(time_t time, uint32 mapid, float x, float y, float z) time_inn_enter = time; } -bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) +bool Player::BuildEnumData(PreparedQueryResult result, ByteBuffer* dataBuffer, ByteBuffer* bitBuffer) { // 0 1 2 3 4 5 6 7 // "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " // 8 9 10 11 12 13 14 // "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " - // 15 16 17 18 19 20 21 - // "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_banned.guid, character_declinedname.genitive " + // 15 16 17 18 19 20 21 22 + // "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_banned.guid, characters.slot, character_declinedname.genitive" Field* fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); + ObjectGuid guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + std::string name = fields[1].GetString(); uint8 plrRace = fields[2].GetUInt8(); uint8 plrClass = fields[3].GetUInt8(); uint8 gender = fields[4].GetUInt8(); - - PlayerInfo const* info = sObjectMgr->GetPlayerInfo(plrRace, plrClass); - if (!info) - { - TC_LOG_ERROR("entities.player.loading", "Player %u has incorrect race/class pair. Don't build enum.", guid); - return false; - } - else if (!IsValidGender(gender)) - { - TC_LOG_ERROR("entities.player.loading", "Player (%u) has incorrect gender (%u), don't build enum.", guid, gender); - return false; - } - - *data << uint64(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); - *data << fields[1].GetString(); // name - *data << uint8(plrRace); // race - *data << uint8(plrClass); // class - *data << uint8(gender); // gender - - uint32 playerBytes = fields[5].GetUInt32(); - *data << uint8(playerBytes); // skin - *data << uint8(playerBytes >> 8); // face - *data << uint8(playerBytes >> 16); // hair style - *data << uint8(playerBytes >> 24); // hair color - - uint32 playerBytes2 = fields[6].GetUInt32(); - *data << uint8(playerBytes2 & 0xFF); // facial hair - - *data << uint8(fields[7].GetUInt8()); // level - *data << uint32(fields[8].GetUInt16()); // zone - *data << uint32(fields[9].GetUInt16()); // map - - *data << fields[10].GetFloat(); // x - *data << fields[11].GetFloat(); // y - *data << fields[12].GetFloat(); // z - - *data << uint32(fields[13].GetUInt32()); // guild id + uint8 skin = uint8(fields[5].GetUInt32() & 0xFF); + uint8 face = uint8((fields[5].GetUInt32() >> 8) & 0xFF); + uint8 hairStyle = uint8((fields[5].GetUInt32() >> 16) & 0xFF); + uint8 hairColor = uint8((fields[5].GetUInt32() >> 24) & 0xFF); + uint8 facialHair = uint8(fields[6].GetUInt32() & 0xFF); + uint8 level = fields[7].GetUInt8(); + uint32 zone = fields[8].GetUInt16(); + uint32 mapId = uint32(fields[9].GetUInt16()); + float x = fields[10].GetFloat(); + float y = fields[11].GetFloat(); + float z = fields[12].GetFloat(); + uint32 guildId = fields[13].GetUInt32(); + ObjectGuid guildGuid = MAKE_NEW_GUID(guildId, 0, guildId ? uint32(HIGHGUID_GUILD) : 0); + uint32 playerFlags = fields[14].GetUInt32(); + uint32 atLoginFlags = fields[15].GetUInt16(); + Tokenizer equipment(fields[19].GetString(), ' '); + uint8 slot = fields[21].GetUInt8(); uint32 charFlags = 0; - uint32 playerFlags = fields[14].GetUInt32(); - uint16 atLoginFlags = fields[15].GetUInt16(); if (playerFlags & PLAYER_FLAGS_HIDE_HELM) charFlags |= CHARACTER_FLAG_HIDE_HELM; + if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK) charFlags |= CHARACTER_FLAG_HIDE_CLOAK; + if (playerFlags & PLAYER_FLAGS_GHOST) charFlags |= CHARACTER_FLAG_GHOST; + if (atLoginFlags & AT_LOGIN_RENAME) charFlags |= CHARACTER_FLAG_RENAME; + if (fields[20].GetUInt32()) charFlags |= CHARACTER_FLAG_LOCKED_BY_BILLING; - if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) - { - if (!fields[21].GetString().empty()) - charFlags |= CHARACTER_FLAG_DECLINED; - } - else - charFlags |= CHARACTER_FLAG_DECLINED; - *data << uint32(charFlags); // character flags + if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED) && !fields[22].GetString().empty()) + charFlags |= CHARACTER_FLAG_DECLINED; - // character customize flags + uint32 customizationFlag = 0; if (atLoginFlags & AT_LOGIN_CUSTOMIZE) - *data << uint32(CHAR_CUSTOMIZE_FLAG_CUSTOMIZE); + customizationFlag = CHAR_CUSTOMIZE_FLAG_CUSTOMIZE; else if (atLoginFlags & AT_LOGIN_CHANGE_FACTION) - *data << uint32(CHAR_CUSTOMIZE_FLAG_FACTION); + customizationFlag = CHAR_CUSTOMIZE_FLAG_FACTION; else if (atLoginFlags & AT_LOGIN_CHANGE_RACE) - *data << uint32(CHAR_CUSTOMIZE_FLAG_RACE); - else - *data << uint32(CHAR_CUSTOMIZE_FLAG_NONE); - - // First login - *data << uint8(atLoginFlags & AT_LOGIN_FIRST ? 1 : 0); + customizationFlag = CHAR_CUSTOMIZE_FLAG_RACE; - // Pets info uint32 petDisplayId = 0; - uint32 petLevel = 0; - uint32 petFamily = 0; - + uint32 petLevel = 0; + uint32 petFamily = 0; // show pet at selection character in character list only for non-ghost character if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (plrClass == CLASS_WARLOCK || plrClass == CLASS_HUNTER || plrClass == CLASS_DEATH_KNIGHT)) { @@ -2017,32 +1993,48 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) if (creatureInfo) { petDisplayId = fields[17].GetUInt32(); - petLevel = fields[18].GetUInt16(); - petFamily = creatureInfo->family; - } - } - - *data << uint32(petDisplayId); - *data << uint32(petLevel); - *data << uint32(petFamily); - - Tokenizer equipment(fields[19].GetString(), ' '); + petLevel = fields[18].GetUInt16(); + petFamily = creatureInfo->family; + } + } + + // Packet content flags + bitBuffer->WriteBit(guid[3]); + bitBuffer->WriteBit(guildGuid[1]); + bitBuffer->WriteBit(guildGuid[7]); + bitBuffer->WriteBit(guildGuid[2]); + bitBuffer->WriteBits(uint32(name.length()), 7); + bitBuffer->WriteBit(guid[4]); + bitBuffer->WriteBit(guid[7]); + bitBuffer->WriteBit(guildGuid[3]); + bitBuffer->WriteBit(guid[5]); + bitBuffer->WriteBit(guildGuid[6]); + bitBuffer->WriteBit(guid[1]); + bitBuffer->WriteBit(guildGuid[5]); + bitBuffer->WriteBit(guildGuid[4]); + bitBuffer->WriteBit(atLoginFlags & AT_LOGIN_FIRST); + bitBuffer->WriteBit(guid[0]); + bitBuffer->WriteBit(guid[2]); + bitBuffer->WriteBit(guid[6]); + bitBuffer->WriteBit(guildGuid[0]); + + // Character data + *dataBuffer << uint8(plrClass); // Class for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) { - uint32 visualBase = slot * 2; - uint32 itemId = GetUInt32ValueFromArray(equipment, visualBase); + uint32 visualbase = slot * 2; + uint32 itemId = GetUInt32ValueFromArray(equipment, visualbase); ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); if (!proto) { - *data << uint32(0); - *data << uint8(0); - *data << uint32(0); + *dataBuffer << uint8(0); + *dataBuffer << uint32(0); + *dataBuffer << uint32(0); continue; } SpellItemEnchantmentEntry const* enchant = NULL; - - uint32 enchants = GetUInt32ValueFromArray(equipment, visualBase + 1); + uint32 enchants = GetUInt32ValueFromArray(equipment, visualbase + 1); for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot) { // values stored in 2 uint16 @@ -2055,11 +2047,47 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) break; } - *data << uint32(proto->DisplayInfoID); - *data << uint8(proto->InventoryType); - *data << uint32(enchant ? enchant->aura_id : 0); - } - + *dataBuffer << uint8(proto->InventoryType); + *dataBuffer << uint32(proto->DisplayInfoID); + *dataBuffer << uint32(enchant ? enchant->aura_id : 0); + } + + *dataBuffer << uint32(petFamily); // Pet family + dataBuffer->WriteByteSeq(guildGuid[2]); + *dataBuffer << uint8(slot); // List order + *dataBuffer << uint8(hairStyle); // Hair style + dataBuffer->WriteByteSeq(guildGuid[3]); + *dataBuffer << uint32(petDisplayId); // Pet DisplayID + *dataBuffer << uint32(charFlags); // Character flags + *dataBuffer << uint8(hairColor); // Hair color + dataBuffer->WriteByteSeq(guid[4]); + *dataBuffer << uint32(mapId); // Map Id + dataBuffer->WriteByteSeq(guildGuid[5]); + *dataBuffer << float(z); // Z + dataBuffer->WriteByteSeq(guildGuid[6]); + *dataBuffer << uint32(petLevel); // Pet level + dataBuffer->WriteByteSeq(guid[3]); + *dataBuffer << float(y); // Y + *dataBuffer << uint32(customizationFlag); // Character customization flags + *dataBuffer << uint8(facialHair); // Facial hair + dataBuffer->WriteByteSeq(guid[7]); + *dataBuffer << uint8(gender); // Gender + dataBuffer->append(name.c_str(), name.length()); // Name + *dataBuffer << uint8(face); // Face + dataBuffer->WriteByteSeq(guid[0]); + dataBuffer->WriteByteSeq(guid[2]); + dataBuffer->WriteByteSeq(guildGuid[1]); + dataBuffer->WriteByteSeq(guildGuid[7]); + *dataBuffer << float(x); // X + *dataBuffer << uint8(skin); // Skin + *dataBuffer << uint8(plrRace); // Race + *dataBuffer << uint8(level); // Level + dataBuffer->WriteByteSeq(guid[6]); + dataBuffer->WriteByteSeq(guildGuid[4]); + dataBuffer->WriteByteSeq(guildGuid[0]); + dataBuffer->WriteByteSeq(guid[5]); + dataBuffer->WriteByteSeq(guid[1]); + *dataBuffer << uint32(zone); // Zone id return true; } @@ -2093,15 +2121,6 @@ uint8 Player::GetChatTag() const return tag; } -void Player::SendTeleportAckPacket() -{ - WorldPacket data(MSG_MOVE_TELEPORT_ACK, 41); - data.append(GetPackGUID()); - data << uint32(0); // this value increments every time - BuildMovementPacket(&data); - GetSession()->SendPacket(&data); -} - bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options) { if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) @@ -2151,13 +2170,12 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // reset movement flags at teleport, because player will continue move with these flags after teleport SetUnitMovementFlags(GetUnitMovementFlags() & MOVEMENTFLAG_MASK_HAS_PLAYER_STATUS_OPCODE); + m_movementInfo.ResetJump(); DisableSpline(); if (Transport* transport = GetTransport()) { - if (options & TELE_TO_NOT_LEAVE_TRANSPORT) - AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - else + if (!(options & TELE_TO_NOT_LEAVE_TRANSPORT)) transport->RemovePassenger(this); } @@ -2199,16 +2217,15 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati SetFallInformation(0, z); // code for finish transfer called in WorldSession::HandleMovementOpcodes() - // at client packet MSG_MOVE_TELEPORT_ACK + // at client packet CMSG_MOVE_TELEPORT_ACK SetSemaphoreTeleportNear(true); - // near teleport, triggering send MSG_MOVE_TELEPORT_ACK from client at landing + // near teleport, triggering send CMSG_MOVE_TELEPORT_ACK from client at landing if (!GetSession()->PlayerLogout()) { Position oldPos = GetPosition(); if (HasUnitMovementFlag(MOVEMENTFLAG_HOVER)) z += GetFloatValue(UNIT_FIELD_HOVERHEIGHT); Relocate(x, y, z, orientation); - SendTeleportAckPacket(); SendTeleportPacket(oldPos); // this automatically relocates to oldPos in order to broadcast the packet in the right place } } @@ -2292,10 +2309,16 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati { // send transfer packets WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4); - data << uint32(mapid); + data.WriteBit(0); // unknown if (Transport* transport = GetTransport()) - data << transport->GetEntry() << GetMapId(); + { + data.WriteBit(1); // has transport + data << GetMapId() << transport->GetEntry(); + } + else + data.WriteBit(0); // has transport + data << uint32(mapid); GetSession()->SendPacket(&data); } @@ -2311,11 +2334,11 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!GetSession()->PlayerLogout()) { WorldPacket data(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4); + data << float(m_teleport_dest.GetPositionX()); + data << float(m_teleport_dest.GetOrientation()); + data << float(m_teleport_dest.GetPositionZ()); data << uint32(mapid); - if (GetTransport()) - data << m_movementInfo.transport.pos.PositionXYZOStream(); - else - data << m_teleport_dest.PositionXYZOStream(); + data << float(m_teleport_dest.GetPositionY()); GetSession()->SendPacket(&data); SendSavedInstances(); @@ -2356,18 +2379,22 @@ void Player::ProcessDelayedOperations() { ResurrectPlayer(0.0f, false); - if (GetMaxHealth() > m_resurrectHealth) - SetHealth(m_resurrectHealth); + if (GetMaxHealth() > _resurrectionData->Health) + SetHealth(_resurrectionData->Health); else SetFullHealth(); - if (GetMaxPower(POWER_MANA) > m_resurrectMana) - SetPower(POWER_MANA, m_resurrectMana); + if (uint32(GetMaxPower(POWER_MANA)) > _resurrectionData->Mana) + SetPower(POWER_MANA, _resurrectionData->Mana); else SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); SetPower(POWER_RAGE, 0); SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); + SetPower(POWER_ECLIPSE, 0); + + if (uint32 aura = _resurrectionData->Aura) + CastSpell(this, aura, true, NULL, NULL, _resurrectionData->GUID); SpawnCorpseBones(); } @@ -2466,15 +2493,40 @@ void Player::RegenerateAll() m_regenTimerCount += m_regenTimer; - Regenerate(POWER_ENERGY); + if (getClass() == CLASS_PALADIN) + m_holyPowerRegenTimerCount += m_regenTimer; + + if (getClass() == CLASS_HUNTER) + m_focusRegenTimerCount += m_regenTimer; + Regenerate(POWER_ENERGY); Regenerate(POWER_MANA); // Runes act as cooldowns, and they don't need to send any data if (getClass() == CLASS_DEATH_KNIGHT) - for (uint8 i = 0; i < MAX_RUNES; ++i) - if (uint32 cd = GetRuneCooldown(i)) - SetRuneCooldown(i, (cd > m_regenTimer) ? cd - m_regenTimer : 0); + { + for (uint8 i = 0; i < MAX_RUNES; i += 2) + { + uint8 runeToRegen = i; + uint32 cd = GetRuneCooldown(i); + uint32 secondRuneCd = GetRuneCooldown(i + 1); + // Regenerate second rune of the same type only after first rune is off the cooldown + if (secondRuneCd && (cd > secondRuneCd || !cd)) + { + runeToRegen = i + 1; + cd = secondRuneCd; + } + + if (cd) + SetRuneCooldown(runeToRegen, (cd > m_regenTimer) ? cd - m_regenTimer : 0); + } + } + + if (m_focusRegenTimerCount >= 1000 && getClass() == CLASS_HUNTER) + { + Regenerate(POWER_FOCUS); + m_focusRegenTimerCount -= 1000; + } if (m_regenTimerCount >= 2000) { @@ -2493,6 +2545,12 @@ void Player::RegenerateAll() m_regenTimerCount -= 2000; } + if (m_holyPowerRegenTimerCount >= 10000 && getClass() == CLASS_PALADIN) + { + Regenerate(POWER_HOLY_POWER); + m_holyPowerRegenTimerCount -= 10000; + } + m_regenTimer = 0; } @@ -2508,33 +2566,44 @@ void Player::Regenerate(Powers power) if (HasAuraTypeWithValue(SPELL_AURA_PREVENT_REGENERATE_POWER, power)) return; + // Skip regeneration for power type we cannot have + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == MAX_POWERS) + return; + float addvalue = 0.0f; + // Powers now benefit from haste. + float rangedHaste = GetFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE); + float meleeHaste = GetFloatValue(PLAYER_FIELD_MOD_HASTE); + float spellHaste = GetFloatValue(UNIT_MOD_CAST_SPEED); + switch (power) { case POWER_MANA: { - bool recentCast = IsUnderLastManaUseEffect(); float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA); - if (getLevel() < 15) - ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA) * (2.066f - (getLevel() * 0.066f)); - - if (recentCast) // Trinity Updates Mana in intervals of 2s, which is correct - addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * 0.001f * m_regenTimer; + if (IsInCombat()) // Trinity Updates Mana in intervals of 2s, which is correct + addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * ((0.001f * m_regenTimer) + CalculatePct(0.001f, spellHaste)); else - addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * 0.001f * m_regenTimer; - } break; - case POWER_RAGE: // Regenerate rage + addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * ((0.001f * m_regenTimer) + CalculatePct(0.001f, spellHaste)); + } + break; + case POWER_RAGE: // Regenerate rage { if (!IsInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN)) { float RageDecreaseRate = sWorld->getRate(RATE_POWER_RAGE_LOSS); - addvalue += -20 * RageDecreaseRate; // 2 rage by tick (= 2 seconds => 1 rage/sec) + addvalue += -25 * RageDecreaseRate / meleeHaste; // 2.5 rage by tick (= 2 seconds => 1.25 rage/sec) } - } break; - case POWER_ENERGY: // Regenerate energy (rogue) - addvalue += 0.01f * m_regenTimer * sWorld->getRate(RATE_POWER_ENERGY); + } + break; + case POWER_FOCUS: + addvalue += (6.0f + CalculatePct(6.0f, rangedHaste)) * sWorld->getRate(RATE_POWER_FOCUS); + break; + case POWER_ENERGY: // Regenerate energy (rogue) + addvalue += ((0.01f * m_regenTimer) + CalculatePct(0.01f, meleeHaste)) * sWorld->getRate(RATE_POWER_ENERGY); break; case POWER_RUNIC_POWER: { @@ -2543,10 +2612,15 @@ void Player::Regenerate(Powers power) float RunicPowerDecreaseRate = sWorld->getRate(RATE_POWER_RUNICPOWER_LOSS); addvalue += -30 * RunicPowerDecreaseRate; // 3 RunicPower by tick } - } break; - case POWER_RUNE: - case POWER_FOCUS: - case POWER_HAPPINESS: + } + break; + case POWER_HOLY_POWER: // Regenerate holy power + { + if (!IsInCombat()) + addvalue += -1.0f; // remove 1 each 10 sec + } + break; + case POWER_RUNES: break; case POWER_HEALTH: return; @@ -2580,7 +2654,7 @@ void Player::Regenerate(Powers power) else return; - addvalue += m_powerFraction[power]; + addvalue += m_powerFraction[powerIndex]; uint32 integerValue = uint32(fabs(addvalue)); if (addvalue < 0.0f) @@ -2588,12 +2662,12 @@ void Player::Regenerate(Powers power) if (curValue > integerValue) { curValue -= integerValue; - m_powerFraction[power] = addvalue + integerValue; + m_powerFraction[powerIndex] = addvalue + integerValue; } else { curValue = 0; - m_powerFraction[power] = 0; + m_powerFraction[powerIndex] = 0; } } else @@ -2603,15 +2677,16 @@ void Player::Regenerate(Powers power) if (curValue > maxValue) { curValue = maxValue; - m_powerFraction[power] = 0; + m_powerFraction[powerIndex] = 0; } else - m_powerFraction[power] = addvalue - integerValue; + m_powerFraction[powerIndex] = addvalue - integerValue; } + if (m_regenTimerCount >= 2000) SetPower(power, curValue); else - UpdateUInt32Value(UNIT_FIELD_POWER1 + power, curValue); + UpdateUInt32Value(UNIT_FIELD_POWER1 + powerIndex, curValue); } void Player::RegenerateHealth() @@ -2623,10 +2698,6 @@ void Player::RegenerateHealth() return; float HealthIncreaseRate = sWorld->getRate(RATE_HEALTH); - - if (getLevel() < 15) - HealthIncreaseRate = sWorld->getRate(RATE_HEALTH) * (2.066f - (getLevel() * 0.066f)); - float addValue = 0.0f; // polymorphed case @@ -2635,9 +2706,15 @@ void Player::RegenerateHealth() // normal regen case (maybe partly in combat case) else if (!IsInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT)) { - addValue = OCTRegenHPPerSpirit() * HealthIncreaseRate; + addValue = HealthIncreaseRate; + if (!IsInCombat()) { + if (getLevel() < 15) + addValue = (0.20f * ((float)GetMaxHealth()) / getLevel() * HealthIncreaseRate); + else + addValue = 0.015f * ((float)GetMaxHealth()) * HealthIncreaseRate; + AuraEffectList const& mModHealthRegenPct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT); for (AuraEffectList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i) AddPct(addValue, (*i)->GetAmount()); @@ -2678,6 +2755,9 @@ void Player::ResetAllPowers() case POWER_RUNIC_POWER: SetPower(POWER_RUNIC_POWER, 0); break; + case POWER_ECLIPSE: + SetPower(POWER_ECLIPSE, 0); + break; default: break; } @@ -2814,23 +2894,10 @@ void Player::SetGameMaster(bool on) getHostileRefManager().setOnlineOfflineState(false); CombatStopWithPets(); - SetPhaseMask(uint32(PHASEMASK_ANYWHERE), false); // see and visible in all phases m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity()); } else { - // restore phase - uint32 newPhase = 0; - AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE); - if (!phases.empty()) - for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - newPhase |= (*itr)->GetMiscValue(); - - if (!newPhase) - newPhase = PHASEMASK_NORMAL; - - SetPhaseMask(newPhase, false); - m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON; setFactionForRace(getRace()); RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); @@ -3020,23 +3087,21 @@ void Player::GiveLevel(uint8 level) PlayerLevelInfo info; sObjectMgr->GetPlayerLevelInfo(getRace(), getClass(), level, &info); - PlayerClassLevelInfo classInfo; - sObjectMgr->GetPlayerClassLevelInfo(getClass(), level, &classInfo); + uint32 basehp = 0, basemana = 0; + sObjectMgr->GetPlayerClassLevelInfo(getClass(), level, basehp, basemana); // send levelup info to client - WorldPacket data(SMSG_LEVELUP_INFO, (4+4+MAX_POWERS*4+MAX_STATS*4)); + WorldPacket data(SMSG_LEVELUP_INFO, (4+4+MAX_POWERS_PER_CLASS*4+MAX_STATS*4)); data << uint32(level); - data << uint32(int32(classInfo.basehealth) - int32(GetCreateHealth())); - // for (int i = 0; i < MAX_POWERS; ++i) // Powers loop (0-6) - data << uint32(int32(classInfo.basemana) - int32(GetCreateMana())); - data << uint32(0); - data << uint32(0); + data << uint32(int32(basehp) - int32(GetCreateHealth())); + // for (int i = 0; i < MAX_STORED_POWERS; ++i) // Powers loop (0-10) + data << uint32(int32(basemana) - int32(GetCreateMana())); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); // end for - for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) // Stats loop (0-4) + for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) // Stats loop (0-4) data << uint32(int32(info.stats[i]) - GetCreateStat(Stats(i))); GetSession()->SendPacket(&data); @@ -3056,8 +3121,8 @@ void Player::GiveLevel(uint8 level) for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) SetCreateStat(Stats(i), info.stats[i]); - SetCreateHealth(classInfo.basehealth); - SetCreateMana(classInfo.basemana); + SetCreateHealth(basehp); + SetCreateMana(basemana); InitTalentForLevel(); InitTaxiNodesForLevel(); @@ -3068,6 +3133,8 @@ void Player::GiveLevel(uint8 level) if (sWorld->getBoolConfig(CONFIG_ALWAYS_MAXSKILL)) // Max weapon skill when leveling up UpdateSkillsToMaxSkillsForLevel(); + _ApplyAllLevelScaleItemMods(true); // Moved to above SetFullHealth so player will have full health from Heirlooms + // set current level health and mana/energy to maximum after applying all mods. SetFullHealth(); SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); @@ -3075,9 +3142,6 @@ void Player::GiveLevel(uint8 level) if (GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE)) SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE)); SetPower(POWER_FOCUS, 0); - SetPower(POWER_HAPPINESS, 0); - - _ApplyAllLevelScaleItemMods(true); // update level to hunter/summon pet if (Pet* pet = GetPet()) @@ -3114,24 +3178,24 @@ void Player::InitTalentForLevel() if (level < 10) { // Remove all talent points - if (m_usedTalentCount > 0) // Free any used talents + if (GetUsedTalentCount() > 0) // Free any used talents { - ResetTalents(true); /// @todo: Has to (collectively) be renamed to ResetTalents + ResetTalents(true); SetFreeTalentPoints(0); } } else { - if (level < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL) || m_specsCount == 0) + if (level < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL) || GetSpecsCount() == 0) { - m_specsCount = 1; - m_activeSpec = 0; + SetSpecsCount(1); + SetActiveSpec(0); } uint32 talentPointsForLevel = CalculateTalentsPoints(); // if used more that have then reset - if (m_usedTalentCount > talentPointsForLevel) + if (GetUsedTalentCount() > talentPointsForLevel) { if (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED)) ResetTalents(true); @@ -3140,7 +3204,7 @@ void Player::InitTalentForLevel() } // else update amount of free points else - SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount); + SetFreeTalentPoints(talentPointsForLevel - GetUsedTalentCount()); } if (!GetSession()->PlayerLoading()) @@ -3152,8 +3216,8 @@ void Player::InitStatsForLevel(bool reapplyMods) if (reapplyMods) //reapply stats values only on .reset stats (level) command _RemoveAllStatBonuses(); - PlayerClassLevelInfo classInfo; - sObjectMgr->GetPlayerClassLevelInfo(getClass(), getLevel(), &classInfo); + uint32 basehp = 0, basemana = 0; + sObjectMgr->GetPlayerClassLevelInfo(getClass(), getLevel(), basehp, basemana); PlayerLevelInfo info; sObjectMgr->GetPlayerLevelInfo(getRace(), getClass(), getLevel(), &info); @@ -3168,6 +3232,9 @@ void Player::InitStatsForLevel(bool reapplyMods) // set default cast time multiplier SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); + SetFloatValue(UNIT_MOD_CAST_HASTE, 1.0f); + SetFloatValue(PLAYER_FIELD_MOD_HASTE, 1.0f); + SetFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE, 1.0f); // reset size before reapply auras SetObjectScale(1.0f); @@ -3179,10 +3246,10 @@ void Player::InitStatsForLevel(bool reapplyMods) for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) SetStat(Stats(i), info.stats[i]); - SetCreateHealth(classInfo.basehealth); + SetCreateHealth(basehp); //set create powers - SetCreateMana(classInfo.basemana); + SetCreateMana(basemana); SetArmor(int32(m_createStats[STAT_AGILITY]*2)); @@ -3193,13 +3260,17 @@ void Player::InitStatsForLevel(bool reapplyMods) SetUInt32Value(index, 0); SetUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, 0); + SetFloatValue(PLAYER_FIELD_MOD_HEALING_PCT, 1.0f); + SetFloatValue(PLAYER_FIELD_MOD_HEALING_DONE_PCT, 1.0f); for (uint8 i = 0; i < 7; ++i) { SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i, 0); SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, 0); - SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT+i, 1.00f); + SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT+i, 1.0f); } + SetFloatValue(PLAYER_FIELD_MOD_SPELL_POWER_PCT, 1.0f); + //reset attack power, damage and attack speed fields SetFloatValue(UNIT_FIELD_BASEATTACKTIME, 2000.0f); SetFloatValue(UNIT_FIELD_BASEATTACKTIME + 1, 2000.0f); // offhand attack time @@ -3211,12 +3282,11 @@ void Player::InitStatsForLevel(bool reapplyMods) SetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, 0.0f); SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, 0.0f); SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, 0.0f); + SetFloatValue(PLAYER_FIELD_WEAPON_DMG_MULTIPLIERS, 1.0f); SetInt32Value(UNIT_FIELD_ATTACK_POWER, 0); - SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, 0); SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, 0.0f); SetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, 0); - SetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS, 0); SetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER, 0.0f); // Base crit values (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset @@ -3230,7 +3300,9 @@ void Player::InitStatsForLevel(bool reapplyMods) SetFloatValue(PLAYER_PARRY_PERCENTAGE, 0.0f); SetFloatValue(PLAYER_BLOCK_PERCENTAGE, 0.0f); - SetUInt32Value(PLAYER_SHIELD_BLOCK, 0); + + // Static 30% damage blocked + SetUInt32Value(PLAYER_SHIELD_BLOCK, 30); // Dodge percentage SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.0f); @@ -3262,9 +3334,9 @@ void Player::InitStatsForLevel(bool reapplyMods) // save new stats for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i) - SetMaxPower(Powers(i), uint32(GetCreatePowers(Powers(i)))); + SetMaxPower(Powers(i), GetCreatePowers(Powers(i))); - SetMaxHealth(classInfo.basehealth); // stamina bonus will applied later + SetMaxHealth(basehp); // stamina bonus will applied later // cleanup mounted state (it will set correctly at aura loading if player saved at mount. SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); @@ -3299,8 +3371,7 @@ void Player::InitStatsForLevel(bool reapplyMods) SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); if (GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE)) SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE)); - SetPower(POWER_FOCUS, 0); - SetPower(POWER_HAPPINESS, 0); + SetPower(POWER_FOCUS, GetMaxPower(POWER_FOCUS)); SetPower(POWER_RUNIC_POWER, 0); // update level to hunter/summon pet @@ -3332,7 +3403,7 @@ void Player::SendInitialSpells() data << uint32(itr->first); data << uint16(0); // it's not slot id - spellCount +=1; + ++spellCount; } data.put<uint16>(countPos, spellCount); // write real count value @@ -3347,7 +3418,7 @@ void Player::SendInitialSpells() data << uint32(itr->first); - data << uint16(itr->second.itemid); // cast item id + data << uint32(itr->second.itemid); // cast item id data << uint16(sEntry->GetCategory()); // spell category // send infinity cooldown in special format @@ -3393,15 +3464,15 @@ void Player::RemoveMail(uint32 id) void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError, uint32 item_guid, uint32 item_count) { WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(mailError == MAIL_ERR_EQUIP_ERROR?4:(mailAction == MAIL_ITEM_TAKEN?4+4:0)))); - data << (uint32) mailId; - data << (uint32) mailAction; - data << (uint32) mailError; + data << uint32(mailId); + data << uint32(mailAction); + data << uint32(mailError); if (mailError == MAIL_ERR_EQUIP_ERROR) - data << (uint32) equipError; + data << uint32(equipError); else if (mailAction == MAIL_ITEM_TAKEN) { - data << (uint32) item_guid; // item guid low? - data << (uint32) item_count; // item count? + data << uint32(item_guid); // item guid low? + data << uint32(item_count); // item count? } GetSession()->SendPacket(&data); } @@ -3493,8 +3564,8 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) return false; } - PlayerTalentMap::iterator itr = m_talents[spec]->find(spellId); - if (itr != m_talents[spec]->end()) + PlayerTalentMap::iterator itr = GetTalentMap(spec)->find(spellId); + if (itr != GetTalentMap(spec)->end()) itr->second->state = PLAYERSPELL_UNCHANGED; else if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId)) { @@ -3507,8 +3578,8 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) if (!rankSpellId || rankSpellId == spellId) continue; - itr = m_talents[spec]->find(rankSpellId); - if (itr != m_talents[spec]->end()) + itr = GetTalentMap(spec)->find(rankSpellId); + if (itr != GetTalentMap(spec)->end()) itr->second->state = PLAYERSPELL_REMOVED; } } @@ -3519,7 +3590,7 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) newtalent->state = state; newtalent->spec = spec; - (*m_talents[spec])[spellId] = newtalent; + (*GetTalentMap(spec))[spellId] = newtalent; return true; } return false; @@ -3772,7 +3843,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent } // update used talent points count - m_usedTalentCount += talentCost; + SetUsedTalentCount(GetUsedTalentCount() + talentCost); // update free primary prof.points (if any, can be none in case GM .learn prof. learning) if (uint32 freeProfs = GetFreePrimaryProfessionPoints()) @@ -3812,12 +3883,6 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent if (_spell_idx->second->AutolearnType == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->id)) LearnDefaultSkill(pSkill->id, 0); - - if (pSkill->id == SKILL_MOUNTS && !Has310Flyer(false)) - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && - spellInfo->Effects[i].CalcValue() == 310) - SetHas310Flyer(true); } } } @@ -3887,10 +3952,21 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const bool need_cast = (!spellInfo->Stances || (form && (spellInfo->Stances & (1 << (form - 1)))) || (!form && (spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT))); + if (spellInfo->AttributesEx8 & SPELL_ATTR8_MASTERY_SPECIALIZATION) + need_cast &= IsCurrentSpecMasterySpell(spellInfo); + //Check CasterAuraStates return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState))); } +bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const +{ + if (TalentTabEntry const* talentTab = sTalentTabStore.LookupEntry(GetPrimaryTalentTree(GetActiveSpec()))) + return spellInfo->Id == talentTab->MasterySpellId[0] || spellInfo->Id == talentTab->MasterySpellId[1]; + + return false; +} + void Player::LearnSpell(uint32 spell_id, bool dependent, bool fromSkill /*= false*/) { PlayerSpellMap::iterator itr = m_spells.find(spell_id); @@ -3903,9 +3979,9 @@ void Player::LearnSpell(uint32 spell_id, bool dependent, bool fromSkill /*= fals // prevent duplicated entires in spell book, also not send if not in world (loading) if (learning && IsInWorld()) { - WorldPacket data(SMSG_LEARNED_SPELL, 6); + WorldPacket data(SMSG_LEARNED_SPELL, 8); data << uint32(spell_id); - data << uint16(0); + data << uint32(0); GetSession()->SendPacket(&data); } @@ -3987,10 +4063,10 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) uint32 talentCosts = GetTalentSpellCost(spell_id); if (talentCosts > 0 && giveTalentPoints) { - if (talentCosts < m_usedTalentCount) - m_usedTalentCount -= talentCosts; + if (talentCosts < GetUsedTalentCount()) + SetUsedTalentCount(GetUsedTalentCount() - talentCosts); else - m_usedTalentCount = 0; + SetUsedTalentCount(0); } // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning) @@ -4038,35 +4114,6 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) } } } - else - { - // not ranked skills - SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spell_id); - - // most likely will never be used, haven't heard of cases where players unlearn a mount - if (Has310Flyer(false) && spellInfo) - { - for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) - { - SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId); - if (!pSkill) - continue; - - if (_spell_idx->second->skillId == SKILL_MOUNTS) - { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && - spellInfo->Effects[i].CalcValue() == 310) - { - Has310Flyer(true, spell_id); // with true as first argument its also used to set/remove the flag - break; - } - } - } - } - } - } // remove dependent spells SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spell_id); @@ -4117,8 +4164,19 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) if (spell_id == 46917 && m_canTitanGrip) SetCanTitanGrip(false); - if (spell_id == 674 && m_canDualWield) - SetCanDualWield(false); + if (m_canDualWield) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + if (spellInfo->IsPassive()) + { + for (int i = 0; i < MAX_SPELL_EFFECTS; i++) + if (spellInfo->Effects[i].Effect == SPELL_EFFECT_DUAL_WIELD) + { + SetCanDualWield(false); + break; + } + } + } if (sWorld->getBoolConfig(CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN)) AutoUnequipOffhandIfNeed(); @@ -4132,40 +4190,6 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) } } -bool Player::Has310Flyer(bool checkAllSpells, uint32 excludeSpellId) -{ - if (!checkAllSpells) - return (m_ExtraFlags & PLAYER_EXTRA_HAS_310_FLYER) != 0; - else - { - SetHas310Flyer(false); - SpellInfo const* spellInfo; - for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if (itr->first == excludeSpellId) - continue; - - SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(itr->first); - for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) - { - if (_spell_idx->second->skillId != SKILL_MOUNTS) - break; // We can break because mount spells belong only to one skillline (at least 310 flyers do) - - spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && - spellInfo->Effects[i].CalcValue() == 310) - { - SetHas310Flyer(true); - return true; - } - } - } - } - - return false; -} - void Player::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */) { m_spellCooldowns.erase(spell_id); @@ -4236,9 +4260,7 @@ void Player::RemoveAllSpellCooldown() { if (!m_spellCooldowns.empty()) { - for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr) - SendClearCooldown(itr->first, this); - + SendClearAllCooldowns(this); m_spellCooldowns.clear(); } } @@ -4316,31 +4338,31 @@ void Player::_SaveSpellCooldowns(SQLTransaction& trans) trans->Append(ss.str().c_str()); } -uint32 Player::ResetTalentsCost() const +uint32 Player::GetNextResetTalentsCost() const { // The first time reset costs 1 gold - if (m_resetTalentsCost < 1*GOLD) + if (GetTalentResetCost() < 1*GOLD) return 1*GOLD; // then 5 gold - else if (m_resetTalentsCost < 5*GOLD) + else if (GetTalentResetCost() < 5*GOLD) return 5*GOLD; // After that it increases in increments of 5 gold - else if (m_resetTalentsCost < 10*GOLD) + else if (GetTalentResetCost() < 10*GOLD) return 10*GOLD; else { - uint64 months = (sWorld->GetGameTime() - m_resetTalentsTime)/MONTH; + uint64 months = (sWorld->GetGameTime() - GetTalentResetTime())/MONTH; if (months > 0) { // This cost will be reduced by a rate of 5 gold per month - int32 new_cost = int32(m_resetTalentsCost - 5*GOLD*months); + int32 new_cost = int32(GetTalentResetCost() - 5*GOLD*months); // to a minimum of 10 gold. return (new_cost < 10*GOLD ? 10*GOLD : new_cost); } else { // After that it increases in increments of 5 gold - int32 new_cost = m_resetTalentsCost + 5*GOLD; + int32 new_cost = GetTalentResetCost() + 5*GOLD; // until it hits a cap of 50 gold. if (new_cost > 50*GOLD) new_cost = 50*GOLD; @@ -4359,7 +4381,7 @@ bool Player::ResetTalents(bool no_cost) uint32 talentPointsForLevel = CalculateTalentsPoints(); - if (m_usedTalentCount == 0) + if (!GetUsedTalentCount()) { SetFreeTalentPoints(talentPointsForLevel); return false; @@ -4369,9 +4391,9 @@ bool Player::ResetTalents(bool no_cost) if (!no_cost && !sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST)) { - cost = ResetTalentsCost(); + cost = GetNextResetTalentsCost(); - if (!HasEnoughMoney(cost)) + if (!HasEnoughMoney(uint64(cost))) { SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0); return false; @@ -4412,27 +4434,43 @@ bool Player::ResetTalents(bool no_cost) if (_spellEntry->Effects[i].TriggerSpell > 0 && _spellEntry->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL) RemoveSpell(_spellEntry->Effects[i].TriggerSpell, true); // if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted - PlayerTalentMap::iterator plrTalent = m_talents[m_activeSpec]->find(talentInfo->RankID[rank]); - if (plrTalent != m_talents[m_activeSpec]->end()) + PlayerTalentMap::iterator plrTalent = GetTalentMap(GetActiveSpec())->find(talentInfo->RankID[rank]); + if (plrTalent != GetTalentMap(GetActiveSpec())->end()) plrTalent->second->state = PLAYERSPELL_REMOVED; } } + // Remove spec specific spells + uint32 const* talentTabs = GetTalentTabPages(getClass()); + for (uint32 i = 0; i < MAX_TALENT_TABS; ++i) + { + if (std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(talentTabs[i])) + for (size_t j = 0; j < specSpells->size(); ++j) + RemoveSpell(specSpells->at(j), true); + + TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabs[i]); + for (uint32 j = 0; j < MAX_MASTERY_SPELLS; ++j) + if (uint32 mastery = talentTabInfo->MasterySpellId[j]) + RemoveAurasDueToSpell(mastery); + } + + + SetPrimaryTalentTree(GetActiveSpec(), 0); + SetFreeTalentPoints(talentPointsForLevel); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); _SaveTalents(trans); _SaveSpells(trans); CharacterDatabase.CommitTransaction(trans); - SetFreeTalentPoints(talentPointsForLevel); - if (!no_cost) { - ModifyMoney(-(int32)cost); + ModifyMoney(-(int64)cost); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS, cost); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS, 1); - m_resetTalentsCost = cost; - m_resetTalentsTime = time(NULL); + SetTalentResetCost(cost); + SetTalentResetTime(time(NULL)); } /* when prev line will dropped use next line @@ -4446,12 +4484,6 @@ bool Player::ResetTalents(bool no_cost) return true; } -void Player::SetFreeTalentPoints(uint32 points) -{ - sScriptMgr->OnPlayerFreeTalentPointsChanged(this, points); - SetUInt32Value(PLAYER_CHARACTER_POINTS1, points); -} - Mail* Player::GetMail(uint32 id) { for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) @@ -4480,13 +4512,6 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); } - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - { - if (m_items[i] == NULL) - continue; - - m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); - } } Unit::BuildCreateUpdateBlockForPlayer(data, target); @@ -4513,13 +4538,6 @@ void Player::DestroyForPlayer(Player* target, bool onDeath) const m_items[i]->DestroyForPlayer(target); } - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - { - if (m_items[i] == NULL) - continue; - - m_items[i]->DestroyForPlayer(target); - } } } @@ -4532,8 +4550,8 @@ bool Player::HasSpell(uint32 spell) const bool Player::HasTalent(uint32 spell, uint8 spec) const { - PlayerTalentMap::const_iterator itr = m_talents[spec]->find(spell); - return (itr != m_talents[spec]->end() && itr->second->state != PLAYERSPELL_REMOVED); + PlayerTalentMap::const_iterator itr = GetTalentMap(spec)->find(spell); + return (itr != GetTalentMap(spec)->end() && itr->second->state != PLAYERSPELL_REMOVED); } bool Player::HasActiveSpell(uint32 spell) const @@ -4692,7 +4710,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC uint32 sender = mailFields[3].GetUInt32(); std::string subject = mailFields[4].GetString(); std::string body = mailFields[5].GetString(); - uint32 money = mailFields[6].GetUInt32(); + uint64 money = mailFields[6].GetUInt64(); bool has_items = mailFields[7].GetBool(); // We can return mail now @@ -5006,24 +5024,6 @@ void Player::DeleteOldCharacters(uint32 keepDays) } } -void Player::SetMovement(PlayerMovementType pType) -{ - WorldPacket data; - switch (pType) - { - case MOVE_ROOT: data.Initialize(SMSG_FORCE_MOVE_ROOT, GetPackGUID().size()+4); break; - case MOVE_UNROOT: data.Initialize(SMSG_FORCE_MOVE_UNROOT, GetPackGUID().size()+4); break; - case MOVE_WATER_WALK: data.Initialize(SMSG_MOVE_WATER_WALK, GetPackGUID().size()+4); break; - case MOVE_LAND_WALK: data.Initialize(SMSG_MOVE_LAND_WALK, GetPackGUID().size()+4); break; - default: - TC_LOG_ERROR("entities.player", "Player::SetMovement: Unsupported move type (%d), data not sent to client.", pType); - return; - } - data.append(GetPackGUID()); - data << uint32(0); - GetSession()->SendPacket(&data); -} - /* Preconditions: - a resurrectable corpse must not be loaded for the player (only bones) - the player must be in world @@ -5062,9 +5062,9 @@ void Player::BuildPlayerRepop() // convert player body to ghost SetHealth(1); - SetMovement(MOVE_WATER_WALK); - if (!GetSession()->isLogingOut()) - SetMovement(MOVE_UNROOT); + SetWaterWalking(true); + if (!GetSession()->isLogingOut() && !HasUnitState(UNIT_STATE_STUNNED)) + SetRooted(false); // BG - remove insignia related RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); @@ -5106,8 +5106,9 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) setDeathState(ALIVE); - SetMovement(MOVE_LAND_WALK); - SetMovement(MOVE_UNROOT); + SetWaterWalking(false); + if (!HasUnitState(UNIT_STATE_STUNNED)) + SetRooted(false); m_deathTimer = 0; @@ -5118,6 +5119,8 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) SetPower(POWER_MANA, uint32(GetMaxPower(POWER_MANA)*restore_percent)); SetPower(POWER_RAGE, 0); SetPower(POWER_ENERGY, uint32(GetMaxPower(POWER_ENERGY)*restore_percent)); + SetPower(POWER_FOCUS, uint32(GetMaxPower(POWER_FOCUS)*restore_percent)); + SetPower(POWER_ECLIPSE, 0); } // trigger update zone for alive state zone updates @@ -5167,7 +5170,7 @@ void Player::KillPlayer() if (IsFlying() && !GetTransport()) GetMotionMaster()->MoveFall(); - SetMovement(MOVE_ROOT); + SetRooted(true); StopMirrorTimers(); //disable timers(bars) @@ -5233,12 +5236,10 @@ void Player::CreateCorpse() flags |= CORPSE_FLAG_HIDE_CLOAK; if (InBattleground() && !InArena()) flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia - corpse->SetUInt32Value(CORPSE_FIELD_FLAGS, flags); + corpse->SetUInt32Value(CORPSE_FIELD_FLAGS, flags); corpse->SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, GetNativeDisplayId()); - corpse->SetUInt32Value(CORPSE_FIELD_GUILD, GetGuildId()); - uint32 iDisplayID; uint32 iIventoryType; uint32 _cfi; @@ -5289,9 +5290,6 @@ void Player::DurabilityLossAll(double percent, bool inventory) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) DurabilityLoss(pItem, percent); - // keys not have durability - //for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) if (Bag* pBag = GetBagByPos(i)) for (uint32 j = 0; j < pBag->GetBagSize(); j++) @@ -5310,6 +5308,8 @@ void Player::DurabilityLoss(Item* item, double percent) if (!pMaxDurability) return; + percent /= GetTotalAuraMultiplier(SPELL_AURA_MOD_DURABILITY_LOSS); + uint32 pDurabilityLoss = uint32(pMaxDurability*percent); if (pDurabilityLoss < 1) @@ -5333,9 +5333,6 @@ void Player::DurabilityPointsLossAll(int32 points, bool inventory) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) DurabilityPointsLoss(pItem, points); - // keys not have durability - //for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) if (Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i)) for (uint32 j = 0; j < pBag->GetBagSize(); j++) @@ -5454,13 +5451,13 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g TotalCost = costs; } - else if (!HasEnoughMoney(costs)) + else if (!HasEnoughMoney(uint64(costs))) { TC_LOG_DEBUG("entities.player.items", "You do not have enough money"); return TotalCost; } else - ModifyMoney(-int32(costs)); + ModifyMoney(-int64(costs)); } } @@ -5481,7 +5478,7 @@ void Player::RepopAtGraveyard() AreaTableEntry const* zone = GetAreaEntryByAreaID(GetAreaId()); // Such zones are considered unreachable as a ghost and the player must be automatically revived - if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < -500.0f) + if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < (zone ? zone->MaxDepth : -500.0f)) { ResurrectPlayer(0.5f); SpawnCorpseBones(); @@ -5507,7 +5504,8 @@ void Player::RepopAtGraveyard() // and don't show spirit healer location if (ClosestGrave) { - TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation()); + float const* orientation = sObjectMgr->GetGraveyardOrientation(ClosestGrave->ID); + TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, orientation ? *orientation : GetOrientation()); if (isDead()) // not send if alive, because it used in TeleportTo() { WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // show spirit healer position on minimap @@ -5518,7 +5516,7 @@ void Player::RepopAtGraveyard() GetSession()->SendPacket(&data); } } - else if (GetPositionZ() < -500.0f) + else if (GetPositionZ() < zone->MaxDepth) TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); } @@ -5572,7 +5570,7 @@ void Player::UpdateLocalChannels(uint32 newZone) if (!cMgr) return; - std::string current_zone_name = current_zone->area_name[GetSession()->GetSessionDbcLocale()]; + std::string current_zone_name = current_zone->area_name; for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i) { @@ -5608,7 +5606,7 @@ void Player::UpdateLocalChannels(uint32 newZone) else currentNameExt = current_zone_name.c_str(); - snprintf(new_channel_name_buf, 100, channel->pattern[m_session->GetSessionDbcLocale()], currentNameExt); + snprintf(new_channel_name_buf, 100, channel->pattern, currentNameExt); joinChannel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID); if (usedChannel) @@ -5623,7 +5621,7 @@ void Player::UpdateLocalChannels(uint32 newZone) } } else - joinChannel = cMgr->GetJoinChannel(channel->pattern[m_session->GetSessionDbcLocale()], channel->ChannelID); + joinChannel = cMgr->GetJoinChannel(channel->pattern, channel->ChannelID); } else removeChannel = usedChannel; @@ -5654,12 +5652,6 @@ void Player::LeaveLFGChannel() } } -void Player::UpdateDefense() -{ - if (UpdateSkill(SKILL_DEFENSE, sWorld->getIntConfig(CONFIG_SKILL_GAIN_DEFENSE))) - UpdateDefenseBonusesMod(); // update dependent from defense skill part -} - void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply) { if (modGroup >= BASEMOD_END || modType >= MOD_END) @@ -5681,7 +5673,6 @@ void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, floa case CRIT_PERCENTAGE: UpdateCritPercentage(BASE_ATTACK); break; case RANGED_CRIT_PERCENTAGE: UpdateCritPercentage(RANGED_ATTACK); break; case OFFHAND_CRIT_PERCENTAGE: UpdateCritPercentage(OFF_ATTACK); break; - case SHIELD_BLOCK_VALUE: UpdateShieldBlockValue(); break; default: break; } } @@ -5714,15 +5705,6 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD]; } -uint32 Player::GetShieldBlockValue() const -{ - float value = (m_auraBaseMod[SHIELD_BLOCK_VALUE][FLAT_MOD] + GetStat(STAT_STRENGTH) * 0.5f - 10)*m_auraBaseMod[SHIELD_BLOCK_VALUE][PCT_MOD]; - - value = (value < 0) ? 0 : value; - - return uint32(value); -} - float Player::GetMeleeCritFromAgility() { uint8 level = getLevel(); @@ -5745,17 +5727,17 @@ void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) // Table for base dodge values const float dodge_base[MAX_CLASSES] = { - 0.036640f, // Warrior - 0.034943f, // Paladin - -0.040873f, // Hunter - 0.020957f, // Rogue - 0.034178f, // Priest + 0.037580f, // Warrior + 0.036520f, // Paladin + -0.054500f, // Hunter + -0.005900f, // Rogue + 0.031830f, // Priest 0.036640f, // DK - 0.021080f, // Shaman - 0.036587f, // Mage - 0.024211f, // Warlock + 0.016750f, // Shaman + 0.034575f, // Mage + 0.020350f, // Warlock 0.0f, // ?? - 0.056097f // Druid + 0.049510f // Druid }; // Crit/agility to dodge/agility coefficient multipliers; 3.2.0 increased required agility by 15% const float crit_to_dodge[MAX_CLASSES] = @@ -5801,13 +5783,13 @@ float Player::GetSpellCritFromIntellect() if (level > GT_MAX_LEVEL) level = GT_MAX_LEVEL; - GtChanceToSpellCritBaseEntry const* critBase = sGtChanceToSpellCritBaseStore.LookupEntry(pclass-1); - GtChanceToSpellCritEntry const* critRatio = sGtChanceToSpellCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); + GtChanceToSpellCritBaseEntry const* critBase = sGtChanceToSpellCritBaseStore.LookupEntry(pclass - 1); + GtChanceToSpellCritEntry const* critRatio = sGtChanceToSpellCritStore.LookupEntry((pclass - 1) * GT_MAX_LEVEL + level - 1); if (critBase == NULL || critRatio == NULL) return 0.0f; - float crit=critBase->base + GetStat(STAT_INTELLECT)*critRatio->ratio; - return crit*100.0f; + float crit = critBase->base + GetStat(STAT_INTELLECT) * critRatio->ratio; + return crit * 100.0f; } float Player::GetRatingMultiplier(CombatRating cr) const @@ -5828,7 +5810,10 @@ float Player::GetRatingMultiplier(CombatRating cr) const float Player::GetRatingBonusValue(CombatRating cr) const { - return float(GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr)) * GetRatingMultiplier(cr); + float baseResult = float(GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr)) * GetRatingMultiplier(cr); + if (cr != CR_RESILIENCE_PLAYER_DAMAGE_TAKEN) + return baseResult; + return float(1.0f - pow(0.99f, baseResult)) * 100.0f; } float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const @@ -5845,29 +5830,6 @@ float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const return 0.0f; } -float Player::OCTRegenHPPerSpirit() -{ - uint8 level = getLevel(); - uint32 pclass = getClass(); - - if (level > GT_MAX_LEVEL) - level = GT_MAX_LEVEL; - - GtOCTRegenHPEntry const* baseRatio = sGtOCTRegenHPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - GtRegenHPPerSptEntry const* moreRatio = sGtRegenHPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1); - if (baseRatio == NULL || moreRatio == NULL) - return 0.0f; - - // Formula from PaperDollFrame script - float spirit = GetStat(STAT_SPIRIT); - float baseSpirit = spirit; - if (baseSpirit > 50) - baseSpirit = 50; - float moreSpirit = spirit - baseSpirit; - float regen = baseSpirit * baseRatio->ratio + moreSpirit * moreRatio->ratio; - return regen; -} - float Player::OCTRegenMPPerSpirit() { uint8 level = getLevel(); @@ -5889,33 +5851,31 @@ float Player::OCTRegenMPPerSpirit() void Player::ApplyRatingMod(CombatRating cr, int32 value, bool apply) { - float oldRating = m_baseRatingValue[cr]; - m_baseRatingValue[cr]+=(apply ? value : -value); + m_baseRatingValue[cr] += (apply ? value : -value); + // explicit affected values - if (cr == CR_HASTE_MELEE || cr == CR_HASTE_RANGED || cr == CR_HASTE_SPELL) - { - float const mult = GetRatingMultiplier(cr); - float const oldVal = oldRating * mult; - float const newVal = m_baseRatingValue[cr] * mult; - switch (cr) - { - case CR_HASTE_MELEE: - ApplyAttackTimePercentMod(BASE_ATTACK, oldVal, false); - ApplyAttackTimePercentMod(OFF_ATTACK, oldVal, false); - ApplyAttackTimePercentMod(BASE_ATTACK, newVal, true); - ApplyAttackTimePercentMod(OFF_ATTACK, newVal, true); - break; - case CR_HASTE_RANGED: - ApplyAttackTimePercentMod(RANGED_ATTACK, oldVal, false); - ApplyAttackTimePercentMod(RANGED_ATTACK, newVal, true); - break; - case CR_HASTE_SPELL: - ApplyCastTimePercentMod(oldVal, false); - ApplyCastTimePercentMod(newVal, true); - break; - default: // shut up compiler warnings - break; - } + float const mult = GetRatingMultiplier(cr); + float const oldVal = m_baseRatingValue[cr] * mult; + float const newVal = m_baseRatingValue[cr] * mult; + + switch (cr) + { + case CR_HASTE_MELEE: + ApplyAttackTimePercentMod(BASE_ATTACK, oldVal, false); + ApplyAttackTimePercentMod(OFF_ATTACK, oldVal, false); + ApplyAttackTimePercentMod(BASE_ATTACK, newVal, true); + ApplyAttackTimePercentMod(OFF_ATTACK, newVal, true); + break; + case CR_HASTE_RANGED: + ApplyAttackTimePercentMod(RANGED_ATTACK, oldVal, false); + ApplyAttackTimePercentMod(RANGED_ATTACK, newVal, true); + break; + case CR_HASTE_SPELL: + ApplyCastTimePercentMod(oldVal, false); + ApplyCastTimePercentMod(newVal, true); + break; + default: // shut up compiler warnings + break; } UpdateRating(cr); @@ -5938,9 +5898,8 @@ void Player::UpdateRating(CombatRating cr) switch (cr) { - case CR_WEAPON_SKILL: // Implemented in Unit::RollMeleeOutcomeAgainst + case CR_WEAPON_SKILL: case CR_DEFENSE_SKILL: - UpdateDefenseBonusesMod(); break; case CR_DODGE: UpdateDodgePercentage(); @@ -5975,15 +5934,12 @@ void Player::UpdateRating(CombatRating cr) if (affectStats) UpdateAllSpellCritChances(); break; - case CR_HIT_TAKEN_MELEE: // Implemented in Unit::MeleeMissChanceCalc - case CR_HIT_TAKEN_RANGED: - break; - case CR_HIT_TAKEN_SPELL: // Implemented in Unit::MagicSpellHitResult - break; - case CR_CRIT_TAKEN_MELEE: // Implemented in Unit::RollMeleeOutcomeAgainst (only for chance to crit) - case CR_CRIT_TAKEN_RANGED: - break; - case CR_CRIT_TAKEN_SPELL: // Implemented in Unit::SpellCriticalBonus (only for chance to crit) + case CR_HIT_TAKEN_MELEE: // Deprecated since Cataclysm + case CR_HIT_TAKEN_RANGED: // Deprecated since Cataclysm + case CR_HIT_TAKEN_SPELL: // Deprecated since Cataclysm + case CR_RESILIENCE_PLAYER_DAMAGE_TAKEN: + case CR_RESILIENCE_CRIT_TAKEN: + case CR_CRIT_TAKEN_SPELL: // Deprecated since Cataclysm break; case CR_HASTE_MELEE: // Implemented in Player::ApplyRatingMod case CR_HASTE_RANGED: @@ -6004,6 +5960,9 @@ void Player::UpdateRating(CombatRating cr) if (affectStats) UpdateArmorPenetration(amount); break; + case CR_MASTERY: + UpdateMastery(); + break; } } @@ -6039,12 +5998,13 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step) if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return false; - uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); - uint32 data = GetUInt32Value(valueIndex); - uint32 value = SKILL_VALUE(data); - uint32 max = SKILL_MAX(data); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; // itr->second.pos % 2 + + uint16 value = GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset); + uint16 max = GetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset); - if ((!max) || (!value) || (value >= max)) + if (!max || !value || value >= max) return false; if (value < max) @@ -6053,7 +6013,7 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step) if (new_value > max) new_value = max; - SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(new_value, max)); + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, new_value); if (itr->second.uState != SKILL_NEW) itr->second.uState = SKILL_CHANGED; @@ -6149,145 +6109,65 @@ bool Player::UpdateFishingSkill() return UpdateSkillPro(SKILL_FISHING, chance*10, gathering_skill_gain); } -// levels sync. with spell requirement for skill levels to learn -// bonus abilities in sSkillLineAbilityStore -// Used only to avoid scan DBC at each skill grow -static uint32 bonusSkillLevels[ ] = {75, 150, 225, 300, 375, 450}; -static const size_t bonusSkillLevelsSize = sizeof(bonusSkillLevels) / sizeof(uint32); - -bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) +bool Player::UpdateSkillPro(uint16 skillId, int32 chance, uint32 step) { - TC_LOG_DEBUG("entities.player.skills", "UpdateSkillPro(SkillId %d, Chance %3.1f%%)", SkillId, Chance / 10.0f); - if (!SkillId) + // levels sync. with spell requirement for skill levels to learn + // bonus abilities in sSkillLineAbilityStore + // Used only to avoid scan DBC at each skill grow + static uint32 bonusSkillLevels[] = { 75, 150, 225, 300, 375, 450, 525 }; + static const size_t bonusSkillLevelsSize = sizeof(bonusSkillLevels) / sizeof(uint32); + + TC_LOG_DEBUG("entities.player.skills", "UpdateSkillPro(SkillId %d, Chance %3.1f%%)", skillId, chance / 10.0f); + if (!skillId) return false; - if (Chance <= 0) // speedup in 0 chance case + if (chance <= 0) // speedup in 0 chance case { - TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% missed", Chance / 10.0f); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% missed", chance / 10.0f); return false; } - SkillStatusMap::iterator itr = mSkillStatus.find(SkillId); + SkillStatusMap::iterator itr = mSkillStatus.find(skillId); if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return false; - uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; // itr->second.pos % 2 - uint32 data = GetUInt32Value(valueIndex); - uint16 SkillValue = SKILL_VALUE(data); - uint16 MaxValue = SKILL_MAX(data); + uint16 value = GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset); + uint16 max = GetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset); - if (!MaxValue || !SkillValue || SkillValue >= MaxValue) + if (!max || !value || value >= max) return false; - int32 Roll = irand(1, 1000); - - if (Roll <= Chance) + if (irand(1, 1000) > chance) { - uint32 new_value = SkillValue+step; - if (new_value > MaxValue) - new_value = MaxValue; - - SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(new_value, MaxValue)); - if (itr->second.uState != SKILL_NEW) - itr->second.uState = SKILL_CHANGED; - for (size_t i = 0; i < bonusSkillLevelsSize; ++i) - { - uint32 bsl = bonusSkillLevels[i]; - if (SkillValue < bsl && new_value >= bsl) - { - LearnSkillRewardedSpells(SkillId, new_value); - break; - } - } - UpdateSkillEnchantments(SkillId, SkillValue, new_value); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, SkillId); - TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% taken", Chance / 10.0f); - return true; + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% missed", chance / 10.0f); + return false; } - TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% missed", Chance / 10.0f); - return false; -} + uint16 new_value = value + step; + if (new_value > max) + new_value = max; -void Player::UpdateWeaponSkill(WeaponAttackType attType) -{ - // no skill gain in pvp - Unit* victim = GetVictim(); - if (victim && victim->GetTypeId() == TYPEID_PLAYER) - return; + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, new_value); + if (itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_CHANGED; - if (IsInFeralForm()) - return; // always maximized SKILL_FERAL_COMBAT in fact - - if (GetShapeshiftForm() == FORM_TREE) - return; // use weapon but not skill up - - if (victim && victim->GetTypeId() == TYPEID_UNIT && (victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_SKILLGAIN)) - return; - - uint32 weapon_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_WEAPON); - - Item* tmpitem = GetWeaponForAttack(attType, true); - if (!tmpitem && attType == BASE_ATTACK) - { - // Keep unarmed & fist weapon skills in sync - UpdateSkill(SKILL_UNARMED, weapon_skill_gain); - UpdateSkill(SKILL_FIST_WEAPONS, weapon_skill_gain); - } - else if (tmpitem && tmpitem->GetTemplate()->SubClass != ITEM_SUBCLASS_WEAPON_FISHING_POLE) + for (size_t i = 0; i < bonusSkillLevelsSize; ++i) { - switch (tmpitem->GetTemplate()->SubClass) + uint32 bsl = bonusSkillLevels[i]; + if (value < bsl && new_value >= bsl) { - case ITEM_SUBCLASS_WEAPON_FISHING_POLE: - break; - case ITEM_SUBCLASS_WEAPON_FIST: - UpdateSkill(SKILL_UNARMED, weapon_skill_gain); - // no break intended - default: - UpdateSkill(tmpitem->GetSkill(), weapon_skill_gain); - break; + LearnSkillRewardedSpells(skillId, new_value); + break; } } - UpdateAllCritPercentages(); -} - -void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool defence) -{ - uint8 plevel = getLevel(); // if defense than victim == attacker - uint8 greylevel = Trinity::XP::GetGrayLevel(plevel); - uint8 moblevel = victim->getLevelForTarget(this); - if (moblevel < greylevel) - return; - - if (moblevel > plevel + 5) - moblevel = plevel + 5; - - uint8 lvldif = moblevel - greylevel; - if (lvldif < 3) - lvldif = 3; - - uint32 skilldif = 5 * plevel - (defence ? GetBaseDefenseSkillValue() : GetBaseWeaponSkillValue(attType)); - if (skilldif <= 0) - return; - - float chance = float(3 * lvldif * skilldif) / plevel; - if (!defence) - if (getClass() == CLASS_WARRIOR || getClass() == CLASS_ROGUE) - chance += chance * 0.02f * GetStat(STAT_INTELLECT); - - chance = chance < 1.0f ? 1.0f : chance; //minimum chance to increase skill is 1% - - if (roll_chance_f(chance)) - { - if (defence) - UpdateDefense(); - else - UpdateWeaponSkill(attType); - } - else - return; + UpdateSkillEnchantments(skillId, value, new_value); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skillId); + TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro Chance=%3.1f%% taken", chance / 10.0f); + return true; } void Player::ModifySkillBonus(uint32 skillid, int32 val, bool talent) @@ -6296,25 +6176,18 @@ void Player::ModifySkillBonus(uint32 skillid, int32 val, bool talent) if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return; - uint32 bonusIndex = PLAYER_SKILL_BONUS_INDEX(itr->second.pos); + uint16 field = itr->second.pos / 2 + (talent ? PLAYER_SKILL_TALENT_0 : PLAYER_SKILL_MODIFIER_0); + uint8 offset = itr->second.pos & 1; // itr->second.pos % 2 - uint32 bonus_val = GetUInt32Value(bonusIndex); - int16 temp_bonus = SKILL_TEMP_BONUS(bonus_val); - int16 perm_bonus = SKILL_PERM_BONUS(bonus_val); + uint16 bonus = GetUInt16Value(field, offset); - if (talent) // permanent bonus stored in high part - SetUInt32Value(bonusIndex, MAKE_SKILL_BONUS(temp_bonus, perm_bonus+val)); - else // temporary/item bonus stored in low part - SetUInt32Value(bonusIndex, MAKE_SKILL_BONUS(temp_bonus+val, perm_bonus)); + SetUInt16Value(field, offset, bonus + val); } void Player::UpdateSkillsForLevel() { - uint16 maxconfskill = sWorld->GetConfigMaxSkillValue(); uint32 maxSkill = GetMaxSkillValueForLevel(); - bool alwaysMaxSkill = sWorld->getBoolConfig(CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL); - for (SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end(); ++itr) { if (itr->second.uState == SKILL_DELETED) @@ -6328,27 +6201,22 @@ void Player::UpdateSkillsForLevel() if (GetSkillRangeType(rcEntry) != SKILL_RANGE_LEVEL) continue; - uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); - uint32 data = GetUInt32Value(valueIndex); - uint32 max = SKILL_MAX(data); - uint32 val = SKILL_VALUE(data); + if (IsWeaponSkill(rcEntry->SkillId)) + continue; + + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; // itr->second.pos % 2 + + //uint16 val = GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset); + uint16 max = GetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset); /// update only level dependent max skill values if (max != 1) { - /// maximize skill always - if (alwaysMaxSkill) - { - SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(maxSkill, maxSkill)); - if (itr->second.uState != SKILL_NEW) - itr->second.uState = SKILL_CHANGED; - } - else if (max != maxconfskill) /// update max skill value if current max skill not maximized - { - SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(val, maxSkill)); - if (itr->second.uState != SKILL_NEW) - itr->second.uState = SKILL_CHANGED; - } + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, maxSkill); + SetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset, maxSkill); + if (itr->second.uState != SKILL_NEW) + itr->second.uState = SKILL_CHANGED; } } } @@ -6361,20 +6229,28 @@ void Player::UpdateSkillsToMaxSkillsForLevel() continue; uint32 pskill = itr->first; - if (IsProfessionOrRidingSkill(pskill)) + SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pskill, getRace(), getClass()); + if (!rcEntry) continue; - uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos); - uint32 data = GetUInt32Value(valueIndex); - uint32 max = SKILL_MAX(data); + + if (IsProfessionOrRidingSkill(rcEntry->SkillId)) + continue; + + if (IsWeaponSkill(rcEntry->SkillId)) + continue; + + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; // itr->second.pos % 2 + + uint16 max = GetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset); if (max > 1) { - SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(max, max)); + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, max); + if (itr->second.uState != SKILL_NEW) itr->second.uState = SKILL_CHANGED; } - if (pskill == SKILL_DEFENSE) - UpdateDefenseBonusesMod(); } } @@ -6391,22 +6267,29 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) //has skill if (itr != mSkillStatus.end() && itr->second.uState != SKILL_DELETED) { - currVal = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; // itr->second.pos % 2 + currVal = GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset); if (newVal) { // if skill value is going down, update enchantments before setting the new value if (newVal < currVal) UpdateSkillEnchantments(id, currVal, newVal); + // update step - SetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos), MAKE_PAIR32(id, step)); + SetUInt16Value(PLAYER_SKILL_STEP_0 + field, offset, step); // update value - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_SKILL_VALUE(newVal, maxVal)); + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, newVal); + SetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset, maxVal); + if (itr->second.uState != SKILL_NEW) itr->second.uState = SKILL_CHANGED; + LearnSkillRewardedSpells(id, newVal); // if skill value is going up, update enchantments after setting the new value if (newVal > currVal) UpdateSkillEnchantments(id, currVal, newVal); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, id); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, id); } @@ -6415,9 +6298,12 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) //remove enchantments needing this skill UpdateSkillEnchantments(id, currVal, 0); // clear skill fields - SetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos), 0); - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), 0); - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos), 0); + SetUInt16Value(PLAYER_SKILL_LINEID_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_STEP_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_MODIFIER_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_TALENT_0 + field, offset, 0); // mark as deleted or simply remove from map if not saved yet if (itr->second.uState != SKILL_NEW) @@ -6430,24 +6316,44 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) if (SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j)) if (pAbility->skillId == id) RemoveSpell(sSpellMgr->GetFirstSpellInChain(pAbility->spellId)); + + // Clear profession lines + if (GetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1) == id) + SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1, 0); + else if (GetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + 1) == id) + SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + 1, 0); } } else if (newVal) //add { currVal = 0; - for (int i=0; i < PLAYER_MAX_SKILLS; ++i) + for (uint32 i = 0; i < PLAYER_MAX_SKILLS; ++i) { - if (!GetUInt32Value(PLAYER_SKILL_INDEX(i))) + uint16 field = i / 2; + uint8 offset = i & 1; // i % 2 + + if (!GetUInt16Value(PLAYER_SKILL_LINEID_0 + field, offset)) { - SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(id); - if (!pSkill) + SkillLineEntry const* skillEntry = sSkillLineStore.LookupEntry(id); + if (!skillEntry) { - TC_LOG_ERROR("entities.player.skills", "Skill not found in SkillLineStore: skill #%u", id); + TC_LOG_ERROR("misc", "Skill not found in SkillLineStore: skill #%u", id); return; } - SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id, step)); - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i), MAKE_SKILL_VALUE(newVal, maxVal)); + SetUInt16Value(PLAYER_SKILL_LINEID_0 + field, offset, id); + if (skillEntry->categoryId == SKILL_CATEGORY_PROFESSION) + { + if (!GetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1)) + SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1, id); + else if (!GetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + 1)) + SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + 1, id); + } + + SetUInt16Value(PLAYER_SKILL_STEP_0 + field, offset, step); + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, newVal); + SetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset, maxVal); + UpdateSkillEnchantments(id, currVal, newVal); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, id); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, id); @@ -6462,8 +6368,8 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) mSkillStatus.insert(SkillStatusMap::value_type(id, SkillStatusData(i, SKILL_NEW))); // apply skill bonuses - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i), 0); - + SetUInt16Value(PLAYER_SKILL_MODIFIER_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_TALENT_0 + field, offset, 0); // temporary bonuses AuraEffectList const& mModSkill = GetAuraEffectsByType(SPELL_AURA_MOD_SKILL); for (AuraEffectList::const_iterator j = mModSkill.begin(); j != mModSkill.end(); ++j) @@ -6502,7 +6408,7 @@ uint16 Player::GetSkillStep(uint16 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - return PAIR32_HIPART(GetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos))); + return GetUInt16Value(PLAYER_SKILL_STEP_0 + itr->second.pos / 2, itr->second.pos & 1); } uint16 Player::GetSkillValue(uint32 skill) const @@ -6514,11 +6420,12 @@ uint16 Player::GetSkillValue(uint32 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos)); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; - int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)))); - result += SKILL_TEMP_BONUS(bonus); - result += SKILL_PERM_BONUS(bonus); + int32 result = int32(GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset)); + result += int32(GetUInt16Value(PLAYER_SKILL_MODIFIER_0 + field, offset)); + result += int32(GetUInt16Value(PLAYER_SKILL_TALENT_0 + field, offset)); return result < 0 ? 0 : result; } @@ -6531,11 +6438,12 @@ uint16 Player::GetMaxSkillValue(uint32 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos)); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; - int32 result = int32(SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)))); - result += SKILL_TEMP_BONUS(bonus); - result += SKILL_PERM_BONUS(bonus); + int32 result = int32(GetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset)); + result += int32(GetUInt16Value(PLAYER_SKILL_MODIFIER_0 + field, offset)); + result += int32(GetUInt16Value(PLAYER_SKILL_TALENT_0 + field, offset)); return result < 0 ? 0 : result; } @@ -6548,7 +6456,10 @@ uint16 Player::GetPureMaxSkillValue(uint32 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - return SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; + + return GetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset); } uint16 Player::GetBaseSkillValue(uint32 skill) const @@ -6560,8 +6471,11 @@ uint16 Player::GetBaseSkillValue(uint32 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)))); - result += SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos))); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; + + int32 result = int32(GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset)); + result += int32(GetUInt16Value(PLAYER_SKILL_TALENT_0 + field, offset)); return result < 0 ? 0 : result; } @@ -6574,7 +6488,10 @@ uint16 Player::GetPureSkillValue(uint32 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; + + return GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset); } int16 Player::GetSkillPermBonusValue(uint32 skill) const @@ -6586,7 +6503,10 @@ int16 Player::GetSkillPermBonusValue(uint32 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - return SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos))); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; + + return GetUInt16Value(PLAYER_SKILL_TALENT_0 + field, offset); } int16 Player::GetSkillTempBonusValue(uint32 skill) const @@ -6598,17 +6518,19 @@ int16 Player::GetSkillTempBonusValue(uint32 skill) const if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED) return 0; - return SKILL_TEMP_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos))); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; + + return GetUInt16Value(PLAYER_SKILL_MODIFIER_0 + field, offset); } void Player::SendActionButtons(uint32 state) const { WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4)); - data << uint8(state); /* state can be 0, 1, 2 - 0 - Looks to be sent when initial action buttons get sent, however on Trinity we use 1 since 0 had some difficulties - 1 - Used in any SMSG_ACTION_BUTTONS packet with button data on Trinity. Only used after spec swaps on retail. + 0 - Sends initial action buttons, client does not validate if we have the spell or not + 1 - Used used after spec swaps, client validates if a spell is known. 2 - Clears the action bars client sided. This is sent during spec swap before unlearning and before sending the new buttons */ if (state != 2) @@ -6622,9 +6544,12 @@ void Player::SendActionButtons(uint32 state) const data << uint32(0); } } + else + data.resize(MAX_ACTION_BUTTONS * 4); // insert crap, client doesnt even parse this for state == 2 + data << uint8(state); GetSession()->SendPacket(&data); - TC_LOG_INFO("network", "SMSG_ACTION_BUTTONS sent '%u' spec '%u' Sent", GetGUIDLow(), m_activeSpec); + TC_LOG_INFO("network", "Action Buttons for '%u' spec '%u' Sent", GetGUIDLow(), GetActiveSpec()); } bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) @@ -6667,6 +6592,7 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) case ACTION_BUTTON_CMACRO: case ACTION_BUTTON_MACRO: case ACTION_BUTTON_EQSET: + case ACTION_BUTTON_DROPDOWN: break; default: TC_LOG_ERROR("entities.player", "Unknown action type %u", type); @@ -7097,16 +7023,12 @@ void Player::UpdateHonorFields() // update yesterday's contribution if (m_lastHonorUpdateTime >= yesterday) { - SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); - // this is the first update today, reset today's contribution - SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); SetUInt32Value(PLAYER_FIELD_KILLS, MAKE_PAIR32(0, kills_today)); } else { // no honor/kills yesterday or today, reset - SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); SetUInt32Value(PLAYER_FIELD_KILLS, 0); } } @@ -7198,7 +7120,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS, victim->getClass()); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_RACE, victim->getRace()); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, GetAreaId()); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, 1, 0, victim); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, 1, 0, 0, victim); } else { @@ -7235,9 +7157,7 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto GetSession()->SendPacket(&data); // add honor points - ModifyHonorPoints(honor); - - ApplyModUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, honor, true); + ModifyCurrency(CURRENCY_TYPE_HONOR_POINTS, int32(honor)); if (InBattleground() && honor > 0) { @@ -7272,82 +7192,441 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto return true; } -void Player::SetHonorPoints(uint32 value) + +void Player::_LoadCurrency(PreparedQueryResult result) { - if (value > sWorld->getIntConfig(CONFIG_MAX_HONOR_POINTS)) - value = sWorld->getIntConfig(CONFIG_MAX_HONOR_POINTS); - SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, value); - if (value) - AddKnownCurrency(ITEM_HONOR_POINTS_ID); + if (!result) + return; + + do + { + Field* fields = result->Fetch(); + + uint16 currencyID = fields[0].GetUInt16(); + + CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(currencyID); + if (!currency) + continue; + + PlayerCurrency cur; + cur.state = PLAYERCURRENCY_UNCHANGED; + cur.weekCount = fields[1].GetUInt32(); + cur.totalCount = fields[2].GetUInt32(); + + _currencyStorage.insert(PlayerCurrenciesMap::value_type(currencyID, cur)); + + } while (result->NextRow()); } -void Player::SetArenaPoints(uint32 value) +void Player::_SaveCurrency(SQLTransaction& trans) { - if (value > sWorld->getIntConfig(CONFIG_MAX_ARENA_POINTS)) - value = sWorld->getIntConfig(CONFIG_MAX_ARENA_POINTS); - SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, value); - if (value) - AddKnownCurrency(ITEM_ARENA_POINTS_ID); + PreparedStatement* stmt = NULL; + for (PlayerCurrenciesMap::iterator itr = _currencyStorage.begin(); itr != _currencyStorage.end(); ++itr) + { + CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(itr->first); + if (!entry) // should never happen + continue; + + switch (itr->second.state) + { + case PLAYERCURRENCY_NEW: + stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_PLAYER_CURRENCY); + stmt->setUInt32(0, GetGUIDLow()); + stmt->setUInt16(1, itr->first); + stmt->setUInt32(2, itr->second.weekCount); + stmt->setUInt32(3, itr->second.totalCount); + trans->Append(stmt); + break; + case PLAYERCURRENCY_CHANGED: + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_CURRENCY); + stmt->setUInt32(0, itr->second.weekCount); + stmt->setUInt32(1, itr->second.totalCount); + stmt->setUInt32(2, GetGUIDLow()); + stmt->setUInt16(3, itr->first); + trans->Append(stmt); + break; + default: + break; + } + + itr->second.state = PLAYERCURRENCY_UNCHANGED; + } } -void Player::ModifyHonorPoints(int32 value, SQLTransaction trans) +void Player::SendNewCurrency(uint32 id) const { - int32 newValue = int32(GetHonorPoints()) + value; - if (newValue < 0) - newValue = 0; - SetHonorPoints(uint32(newValue)); + PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id); + if (itr == _currencyStorage.end()) + return; + + ByteBuffer currencyData; + WorldPacket packet(SMSG_INIT_CURRENCY, 4 + (5*4 + 1)); + packet.WriteBits(1, 23); + + CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(id); + if (!entry) // should never happen + return; + + uint32 precision = (entry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1; + uint32 weekCount = itr->second.weekCount / precision; + uint32 weekCap = GetCurrencyWeekCap(entry) / precision; + + packet.WriteBit(weekCount); + packet.WriteBits(0, 4); // some flags + packet.WriteBit(weekCap); + packet.WriteBit(0); // season total earned + + currencyData << uint32(itr->second.totalCount / precision); + if (weekCap) + currencyData << uint32(weekCap); + + //if (seasonTotal) + // currencyData << uint32(seasonTotal / precision); - if (trans) + currencyData << uint32(entry->ID); + if (weekCount) + currencyData << uint32(weekCount); + + packet.FlushBits(); + packet.append(currencyData); + GetSession()->SendPacket(&packet); +} + +void Player::SendCurrencies() const +{ + ByteBuffer currencyData; + WorldPacket packet(SMSG_INIT_CURRENCY, 4 + _currencyStorage.size()*(5*4 + 1)); + size_t count_pos = packet.bitwpos(); + packet.WriteBits(_currencyStorage.size(), 23); + + size_t count = 0; + for (PlayerCurrenciesMap::const_iterator itr = _currencyStorage.begin(); itr != _currencyStorage.end(); ++itr) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_HONOR_POINTS); - stmt->setUInt32(0, newValue); - stmt->setUInt32(1, GetGUIDLow()); - trans->Append(stmt); + CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(itr->first); + + // not send init meta currencies. + if (!entry || entry->Category == CURRENCY_CATEGORY_META_CONQUEST) + continue; + + uint32 precision = (entry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1; + uint32 weekCount = itr->second.weekCount / precision; + uint32 weekCap = GetCurrencyWeekCap(entry) / precision; + + packet.WriteBit(weekCount); + packet.WriteBits(0, 4); // some flags + packet.WriteBit(weekCap); + packet.WriteBit(0); // season total earned + + currencyData << uint32(itr->second.totalCount / precision); + if (weekCap) + currencyData << uint32(weekCap); + + //if (seasonTotal) + // currencyData << uint32(seasonTotal / precision); + + currencyData << uint32(entry->ID); + if (weekCount) + currencyData << uint32(weekCount); + + ++count; } + + packet.FlushBits(); + packet.append(currencyData); + packet.PutBits(count_pos, count, 23); + GetSession()->SendPacket(&packet); +} + +void Player::SendPvpRewards() const +{ + WorldPacket packet(SMSG_REQUEST_PVP_REWARDS_RESPONSE, 24); + packet << GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_POINTS, true); + packet << GetCurrencyOnWeek(CURRENCY_TYPE_CONQUEST_POINTS, true); + packet << GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_META_ARENA, true); + packet << GetCurrencyOnWeek(CURRENCY_TYPE_CONQUEST_META_RBG, true); + packet << GetCurrencyOnWeek(CURRENCY_TYPE_CONQUEST_META_ARENA, true); + packet << GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_POINTS, true); + packet << GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_META_RBG, true); + GetSession()->SendPacket(&packet); } -void Player::ModifyArenaPoints(int32 value, SQLTransaction trans) +uint32 Player::GetCurrency(uint32 id, bool usePrecision) const { - int32 newValue = int32(GetArenaPoints()) + value; - if (newValue < 0) - newValue = 0; - SetArenaPoints(uint32(newValue)); + PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id); + if (itr == _currencyStorage.end()) + return 0; + + CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(id); + uint32 precision = (usePrecision && currency->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1; + + return itr->second.totalCount / precision; +} + +uint32 Player::GetCurrencyOnWeek(uint32 id, bool usePrecision) const +{ + PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id); + if (itr == _currencyStorage.end()) + return 0; + + CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(id); + uint32 precision = (usePrecision && currency->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1; + + return itr->second.weekCount / precision; +} + +bool Player::HasCurrency(uint32 id, uint32 count) const +{ + PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id); + return itr != _currencyStorage.end() && itr->second.totalCount >= count; +} + +void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bool ignoreMultipliers/* = false*/) +{ + if (!count) + return; - if (trans) + CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(id); + ASSERT(currency); + + if (!ignoreMultipliers) + count *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_CURRENCY_GAIN, id); + + int32 precision = currency->Flags & CURRENCY_FLAG_HIGH_PRECISION ? CURRENCY_PRECISION : 1; + uint32 oldTotalCount = 0; + uint32 oldWeekCount = 0; + PlayerCurrenciesMap::iterator itr = _currencyStorage.find(id); + if (itr == _currencyStorage.end()) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ARENA_POINTS); - stmt->setUInt32(0, newValue); - stmt->setUInt32(1, GetGUIDLow()); - trans->Append(stmt); + PlayerCurrency cur; + cur.state = PLAYERCURRENCY_NEW; + cur.totalCount = 0; + cur.weekCount = 0; + _currencyStorage[id] = cur; + itr = _currencyStorage.find(id); + } + else + { + oldTotalCount = itr->second.totalCount; + oldWeekCount = itr->second.weekCount; + } + + // count can't be more then weekCap if used (weekCap > 0) + uint32 weekCap = GetCurrencyWeekCap(currency); + if (weekCap && count > int32(weekCap)) + count = weekCap; + + // count can't be more then totalCap if used (totalCap > 0) + uint32 totalCap = GetCurrencyTotalCap(currency); + if (totalCap && count > int32(totalCap)) + count = totalCap; + + int32 newTotalCount = int32(oldTotalCount) + count; + if (newTotalCount < 0) + newTotalCount = 0; + + int32 newWeekCount = int32(oldWeekCount) + (count > 0 ? count : 0); + if (newWeekCount < 0) + newWeekCount = 0; + + // if we get more then weekCap just set to limit + if (weekCap && int32(weekCap) < newWeekCount) + { + newWeekCount = int32(weekCap); + // weekCap - oldWeekCount always >= 0 as we set limit before! + newTotalCount = oldTotalCount + (weekCap - oldWeekCount); + } + + // if we get more then totalCap set to maximum; + if (totalCap && int32(totalCap) < newTotalCount) + { + newTotalCount = int32(totalCap); + newWeekCount = weekCap; + } + + if (uint32(newTotalCount) != oldTotalCount) + { + if (itr->second.state != PLAYERCURRENCY_NEW) + itr->second.state = PLAYERCURRENCY_CHANGED; + + itr->second.totalCount = newTotalCount; + itr->second.weekCount = newWeekCount; + + if (count > 0) + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CURRENCY, id, count); + + if (currency->Category == CURRENCY_CATEGORY_META_CONQUEST) + { + // count was changed to week limit, now we can modify original points. + ModifyCurrency(CURRENCY_TYPE_CONQUEST_POINTS, count, printLog); + return; + } + + WorldPacket packet(SMSG_UPDATE_CURRENCY, 12); + + packet.WriteBit(weekCap != 0); + packet.WriteBit(0); // hasSeasonCount + packet.WriteBit(!printLog); // print in log + + // if hasSeasonCount packet << uint32(seasontotalearned); TODO: save this in character DB and use it + + packet << uint32(newTotalCount / precision); + packet << uint32(id); + if (weekCap) + packet << uint32(newWeekCount / precision); + + GetSession()->SendPacket(&packet); + } +} + +void Player::SetCurrency(uint32 id, uint32 count, bool /*printLog*/ /*= true*/) +{ + PlayerCurrenciesMap::iterator itr = _currencyStorage.find(id); + if (itr == _currencyStorage.end()) + { + PlayerCurrency cur; + cur.state = PLAYERCURRENCY_NEW; + cur.totalCount = count; + cur.weekCount = 0; + _currencyStorage[id] = cur; } } +uint32 Player::GetCurrencyWeekCap(uint32 id, bool usePrecision) const +{ + CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(id); + if (!entry) + return 0; + + uint32 precision = (usePrecision && entry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1; + + return GetCurrencyWeekCap(entry) / precision; +} + +void Player::ResetCurrencyWeekCap() +{ + for (uint32 arenaSlot = 0; arenaSlot < MAX_ARENA_SLOT; arenaSlot++) + { + if (uint32 arenaTeamId = GetArenaTeamId(arenaSlot)) + { + ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); + arenaTeam->FinishWeek(); // set played this week etc values to 0 in memory, too + arenaTeam->SaveToDB(); // save changes + arenaTeam->NotifyStatsChanged(); // notify the players of the changes + } + } + + for (PlayerCurrenciesMap::iterator itr = _currencyStorage.begin(); itr != _currencyStorage.end(); ++itr) + { + itr->second.weekCount = 0; + itr->second.state = PLAYERCURRENCY_CHANGED; + } + + WorldPacket data(SMSG_WEEKLY_RESET_CURRENCY, 0); + SendDirectMessage(&data); +} + +uint32 Player::GetCurrencyWeekCap(CurrencyTypesEntry const* currency) const +{ + switch (currency->ID) + { + //original conquest not have week cap + case CURRENCY_TYPE_CONQUEST_POINTS: + return std::max(GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_META_ARENA, false), GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_META_RBG, false)); + case CURRENCY_TYPE_CONQUEST_META_ARENA: + // should add precision mod = 100 + return Trinity::Currency::ConquestRatingCalculator(_maxPersonalArenaRate) * CURRENCY_PRECISION; + case CURRENCY_TYPE_CONQUEST_META_RBG: + // should add precision mod = 100 + return Trinity::Currency::BgConquestRatingCalculator(GetRBGPersonalRating()) * CURRENCY_PRECISION; + } + + return currency->WeekCap; +} + +uint32 Player::GetCurrencyTotalCap(CurrencyTypesEntry const* currency) const +{ + uint32 cap = currency->TotalCap; + + switch (currency->ID) + { + case CURRENCY_TYPE_HONOR_POINTS: + { + uint32 honorcap = sWorld->getIntConfig(CONFIG_CURRENCY_MAX_HONOR_POINTS); + if (honorcap > 0) + cap = honorcap; + break; + } + case CURRENCY_TYPE_JUSTICE_POINTS: + { + uint32 justicecap = sWorld->getIntConfig(CONFIG_CURRENCY_MAX_JUSTICE_POINTS); + if (justicecap > 0) + cap = justicecap; + break; + } + } + + return cap; +} + +void Player::UpdateConquestCurrencyCap(uint32 currency) +{ + uint32 currenciesToUpdate[2] = { currency, CURRENCY_TYPE_CONQUEST_POINTS }; + + for (uint32 i = 0; i < 2; ++i) + { + CurrencyTypesEntry const* currencyEntry = sCurrencyTypesStore.LookupEntry(currenciesToUpdate[i]); + if (!currencyEntry) + continue; + + uint32 precision = (currencyEntry->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? 100 : 1; + uint32 cap = GetCurrencyWeekCap(currencyEntry); + + WorldPacket packet(SMSG_UPDATE_CURRENCY_WEEK_LIMIT, 8); + packet << uint32(cap / precision); + packet << uint32(currenciesToUpdate[i]); + GetSession()->SendPacket(&packet); + } +} + +void Player::SetInGuild(uint32 guildId) +{ + if (guildId) + SetUInt64Value(OBJECT_FIELD_DATA, MAKE_NEW_GUID(guildId, 0, HIGHGUID_GUILD)); + else + SetUInt64Value(OBJECT_FIELD_DATA, 0); + + ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_GUILD_LEVEL_ENABLED, guildId != 0 && sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED)); + SetUInt16Value(OBJECT_FIELD_TYPE, 1, guildId != 0); +} + uint32 Player::GetGuildIdFromDB(uint64 guid) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); stmt->setUInt32(0, GUID_LOPART(guid)); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - - if (!result) - return 0; + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + return result->Fetch()[0].GetUInt32(); - uint32 id = result->Fetch()[0].GetUInt32(); - return id; + return 0; } uint8 Player::GetRankFromDB(uint64 guid) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); stmt->setUInt32(0, GUID_LOPART(guid)); - PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + return result->Fetch()[1].GetUInt8(); - if (result) + return 0; +} + +void Player::SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value) +{ + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + type, value); + if (type == ARENA_TEAM_PERSONAL_RATING && value > _maxPersonalArenaRate) { - uint32 v = result->Fetch()[1].GetUInt8(); - return v; + _maxPersonalArenaRate = value; + UpdateConquestCurrencyCap(CURRENCY_TYPE_CONQUEST_META_ARENA); } - else - return 0; } void Player::SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type) @@ -7355,10 +7634,6 @@ void Player::SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type) SetArenaTeamInfoField(slot, ARENA_TEAM_ID, ArenaTeamId); SetArenaTeamInfoField(slot, ARENA_TEAM_TYPE, type); } -void Player::SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value) -{ - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + type, value); -} uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type) { @@ -7500,7 +7775,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) if (!zone) return; - if (sWorld->getBoolConfig(CONFIG_WEATHER)) + if (sWorld->getBoolConfig(CONFIG_WEATHER) && !HasAuraType(SPELL_AURA_FORCE_WEATHER)) { if (Weather* weather = WeatherMgr::FindWeather(zone->ID)) weather->SendWeatherUpdateToPlayer(this); @@ -7762,10 +8037,6 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply) _ApplyWeaponDependentAuraMods(item, WeaponAttackType(attacktype), apply); _ApplyItemBonuses(proto, slot, apply); - - if (slot == EQUIPMENT_SLOT_RANGED) - _ApplyAmmoBonuses(); - ApplyItemEquipSpell(item, apply); ApplyEnchantment(item, apply); @@ -7786,7 +8057,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply if (ssd && ssd_level > ssd->MaxLevel) ssd_level = ssd->MaxLevel; - ScalingStatValuesEntry const* ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(ssd_level) : NULL; + ScalingStatValuesEntry const* ssv = ssd ? sScalingStatValuesStore.LookupEntry(ssd_level) : NULL; if (only_level_scale && !ssv) return; @@ -7800,12 +8071,10 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply if (ssd->StatMod[i] < 0) continue; statType = ssd->StatMod[i]; - val = (ssv->getssdMultiplier(proto->ScalingStatValue) * ssd->Modifier[i]) / 10000; + val = (ssv->GetStatMultiplier(proto->InventoryType) * ssd->Modifier[i]) / 10000; } else { - if (i >= proto->StatsCount) - continue; statType = proto->ItemStat[i].ItemStatType; val = proto->ItemStat[i].ItemStatValue; } @@ -7871,24 +8140,24 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply case ITEM_MOD_CRIT_SPELL_RATING: ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply); break; - case ITEM_MOD_HIT_TAKEN_MELEE_RATING: - ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply); - break; - case ITEM_MOD_HIT_TAKEN_RANGED_RATING: - ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply); - break; - case ITEM_MOD_HIT_TAKEN_SPELL_RATING: - ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply); - break; - case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); - break; + // case ITEM_MOD_HIT_TAKEN_MELEE_RATING: + // ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply); + // break; + // case ITEM_MOD_HIT_TAKEN_RANGED_RATING: + // ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply); + // break; + // case ITEM_MOD_HIT_TAKEN_SPELL_RATING: + // ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply); + // break; + // case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: + // ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); + // break; case ITEM_MOD_CRIT_TAKEN_RANGED_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); - break; - case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); + ApplyRatingMod(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN, int32(val), apply); break; + // case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: + // ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); + // break; case ITEM_MOD_HASTE_MELEE_RATING: ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply); break; @@ -7908,20 +8177,18 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply); ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply); break; - case ITEM_MOD_HIT_TAKEN_RATING: - ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply); - ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply); - ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply); - break; - case ITEM_MOD_CRIT_TAKEN_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); - ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); - ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); - break; + // case ITEM_MOD_HIT_TAKEN_RATING: // Unused since 3.3.5 + // ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply); + // ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply); + // ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply); + // break; + // case ITEM_MOD_CRIT_TAKEN_RATING: // Unused since 3.3.5 + // ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); + // ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); + // ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); + // break; case ITEM_MOD_RESILIENCE_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply); - ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply); - ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply); + ApplyRatingMod(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN, int32(val), apply); break; case ITEM_MOD_HASTE_RATING: ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply); @@ -7938,9 +8205,6 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply case ITEM_MOD_RANGED_ATTACK_POWER: HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); break; -// case ITEM_MOD_FERAL_ATTACK_POWER: -// ApplyFeralAPBonus(int32(val), apply); -// break; case ITEM_MOD_MANA_REGENERATION: ApplyManaRegenBonus(int32(val), apply); break; @@ -7956,28 +8220,39 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply case ITEM_MOD_SPELL_PENETRATION: ApplySpellPenetrationBonus(val, apply); break; - case ITEM_MOD_BLOCK_VALUE: - HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(val), apply); + case ITEM_MOD_MASTERY_RATING: + ApplyRatingMod(CR_MASTERY, int32(val), apply); + break; + case ITEM_MOD_FIRE_RESISTANCE: + HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(val), apply); + break; + case ITEM_MOD_FROST_RESISTANCE: + HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(val), apply); + break; + case ITEM_MOD_HOLY_RESISTANCE: + HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(val), apply); + break; + case ITEM_MOD_SHADOW_RESISTANCE: + HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(val), apply); break; - // deprecated item mods - case ITEM_MOD_SPELL_HEALING_DONE: - case ITEM_MOD_SPELL_DAMAGE_DONE: + case ITEM_MOD_NATURE_RESISTANCE: + HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(val), apply); + break; + case ITEM_MOD_ARCANE_RESISTANCE: + HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(val), apply); break; } } // Apply Spell Power from ScalingStatValue if set - if (ssv) - if (int32 spellbonus = ssv->getSpellBonus(proto->ScalingStatValue)) + if (ssv && proto->Flags2 & ITEM_FLAGS_EXTRA_CASTER_WEAPON) + if (int32 spellbonus = int32(ssv->Spellpower)) ApplySpellPowerBonus(spellbonus, apply); // If set ScalingStatValue armor get it or use item armor uint32 armor = proto->Armor; - if (ssv) - { - if (uint32 ssvarmor = ssv->getArmorMod(proto->ScalingStatValue)) - armor = ssvarmor; - } + if (ssv && proto->Class == ITEM_CLASS_ARMOR) + armor = ssv->GetArmor(proto->InventoryType, proto->SubClass - 1); else if (armor && proto->ArmorDamageModifier) armor -= uint32(proto->ArmorDamageModifier); @@ -8004,27 +8279,6 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply if (proto->ArmorDamageModifier > 0) HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply); - if (proto->Block) - HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply); - - if (proto->HolyRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply); - - if (proto->FireRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply); - - if (proto->NatureRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply); - - if (proto->FrostRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply); - - if (proto->ShadowRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply); - - if (proto->ArcaneRes) - HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply); - WeaponAttackType attType = BASE_ATTACK; if (slot == EQUIPMENT_SLOT_RANGED && ( @@ -8040,23 +8294,6 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply if (CanUseAttackType(attType)) _ApplyWeaponDamage(slot, proto, ssv, apply); - - - // Druids get feral AP bonus from weapon dps (also use DPS from ScalingStatValue) - if (getClass() == CLASS_DRUID) - { - int32 dpsMod = 0; - int32 feral_bonus = 0; - if (ssv) - { - dpsMod = ssv->getDPSMod(proto->ScalingStatValue); - feral_bonus += ssv->getFeralBonus(proto->ScalingStatValue); - } - - feral_bonus += proto->getFeralBonus(dpsMod); - if (feral_bonus) - ApplyFeralAPBonus(feral_bonus, apply); - } } void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv, bool apply) @@ -8075,18 +8312,20 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt attType = OFF_ATTACK; } - float minDamage = proto->Damage[0].DamageMin; - float maxDamage = proto->Damage[0].DamageMax; + float minDamage = proto->DamageMin; + float maxDamage = proto->DamageMax; // If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage + int32 extraDPS = 0; if (ssv) { - int32 extraDPS = ssv->getDPSMod(proto->ScalingStatValue); + float damageMultiplier = 0.0f; + extraDPS = ssv->GetDPSAndDamageMultiplier(proto->SubClass, (proto->Flags2 & ITEM_FLAGS_EXTRA_CASTER_WEAPON) != 0, &damageMultiplier); if (extraDPS) { float average = extraDPS * proto->Delay / 1000.0f; - minDamage = 0.7f * average; - maxDamage = 1.3f * average; + minDamage = (1.0f - damageMultiplier) * average; + maxDamage = (1.0f + damageMultiplier) * average; } } @@ -8112,10 +8351,6 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt SetAttackTime(OFF_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME); } - // No need to modify any physical damage for ferals as it is calculated from stats only - if (IsInFeralForm()) - return; - if (CanModifyStats() && (damage || proto->Delay)) UpdateDamagePhysical(attType); } @@ -8364,10 +8599,10 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 float chance = (float)spellInfo->ProcChance; - if (spellData.SpellPPMRate) + if (proto->SpellPPMRate) { uint32 WeaponSpeed = GetAttackTime(attType); - chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate, spellInfo); + chance = GetPPMProcChance(WeaponSpeed, proto->SpellPPMRate, spellInfo); } else if (chance > 100.0f) chance = GetWeaponProcChance(); @@ -8380,6 +8615,9 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 // item combat enchantments for (uint8 e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot) { + if (e_slot > PRISMATIC_ENCHANTMENT_SLOT && e_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id + continue; + uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot)); SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!pEnchant) @@ -8455,7 +8693,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 if (!spellInfo) { TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) in have wrong spell id %u, ignoring ", proto->ItemId, learn_spell_id); - SendEquipError(EQUIP_ERR_NONE, item, NULL); + SendEquipError(EQUIP_ERR_INTERNAL_BAG_ERROR, item, NULL); return; } @@ -8502,6 +8740,9 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 // Item enchantments spells cast at use for (uint8 e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot) { + if (e_slot > PRISMATIC_ENCHANTMENT_SLOT && e_slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id + continue; + uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot)); SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!pEnchant) @@ -8568,9 +8809,6 @@ void Player::_RemoveAllItemMods() _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), false); _ApplyItemBonuses(proto, i, false); - - if (i == EQUIPMENT_SLOT_RANGED) - _ApplyAmmoBonuses(); } } @@ -8597,9 +8835,6 @@ void Player::_ApplyAllItemMods() _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), true); _ApplyItemBonuses(proto, i, true); - - if (i == EQUIPMENT_SLOT_RANGED) - _ApplyAmmoBonuses(); } } @@ -8644,63 +8879,6 @@ void Player::_ApplyAllLevelScaleItemMods(bool apply) } } -void Player::_ApplyAmmoBonuses() -{ - // check ammo - uint32 ammo_id = GetUInt32Value(PLAYER_AMMO_ID); - if (!ammo_id) - return; - - float currentAmmoDPS; - - ItemTemplate const* ammo_proto = sObjectMgr->GetItemTemplate(ammo_id); - if (!ammo_proto || ammo_proto->Class != ITEM_CLASS_PROJECTILE || !CheckAmmoCompatibility(ammo_proto)) - currentAmmoDPS = 0.0f; - else - currentAmmoDPS = (ammo_proto->Damage[0].DamageMin + ammo_proto->Damage[0].DamageMax) / 2; - - if (currentAmmoDPS == GetAmmoDPS()) - return; - - m_ammoDPS = currentAmmoDPS; - - if (CanModifyStats()) - UpdateDamagePhysical(RANGED_ATTACK); -} - -bool Player::CheckAmmoCompatibility(const ItemTemplate* ammo_proto) const -{ - if (!ammo_proto) - return false; - - // check ranged weapon - Item* weapon = GetWeaponForAttack(RANGED_ATTACK); - if (!weapon || weapon->IsBroken()) - return false; - - ItemTemplate const* weapon_proto = weapon->GetTemplate(); - if (!weapon_proto || weapon_proto->Class != ITEM_CLASS_WEAPON) - return false; - - // check ammo ws. weapon compatibility - switch (weapon_proto->SubClass) - { - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - if (ammo_proto->SubClass != ITEM_SUBCLASS_ARROW) - return false; - break; - case ITEM_SUBCLASS_WEAPON_GUN: - if (ammo_proto->SubClass != ITEM_SUBCLASS_BULLET) - return false; - break; - default: - return false; - } - - return true; -} - /* If in a battleground a player dies, and an enemy removes the insignia, the player's bones is lootable Called by remove insignia spell effect */ void Player::RemovedInsignia(Player* looterPlr) @@ -9047,7 +9225,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) // need know merged fishing/corpse loot type for achievements loot->loot_type = loot_type; - WorldPacket data(SMSG_LOOT_RESPONSE, (9+50)); // we guess size + WorldPacket data(SMSG_LOOT_RESPONSE, 8 + 1 + 50 + 1 + 1); // we guess size data << uint64(guid); data << uint8(loot_type); data << LootView(*loot, this, permission); @@ -9077,9 +9255,10 @@ void Player::SendNotifyLootItemRemoved(uint8 lootSlot) void Player::SendUpdateWorldState(uint32 Field, uint32 Value) { - WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); + WorldPacket data(SMSG_UPDATE_WORLD_STATE, 4+4+1); data << Field; data << Value; + data << uint8(0); GetSession()->SendPacket(&data); } @@ -9132,46 +9311,6 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) case 2257: // Deeprun Tram case 3703: // Shattrath City break; - case 139: // Eastern Plaguelands - if (pvp && pvp->GetTypeId() == OUTDOOR_PVP_EP) - pvp->FillInitialWorldStates(data); - else - { - data << uint32(0x97a) << uint32(0x0); // 10 2426 - data << uint32(0x917) << uint32(0x0); // 11 2327 - data << uint32(0x918) << uint32(0x0); // 12 2328 - data << uint32(0x97b) << uint32(0x32); // 13 2427 - data << uint32(0x97c) << uint32(0x32); // 14 2428 - data << uint32(0x933) << uint32(0x1); // 15 2355 - data << uint32(0x946) << uint32(0x0); // 16 2374 - data << uint32(0x947) << uint32(0x0); // 17 2375 - data << uint32(0x948) << uint32(0x0); // 18 2376 - data << uint32(0x949) << uint32(0x0); // 19 2377 - data << uint32(0x94a) << uint32(0x0); // 20 2378 - data << uint32(0x94b) << uint32(0x0); // 21 2379 - data << uint32(0x932) << uint32(0x0); // 22 2354 - data << uint32(0x934) << uint32(0x0); // 23 2356 - data << uint32(0x935) << uint32(0x0); // 24 2357 - data << uint32(0x936) << uint32(0x0); // 25 2358 - data << uint32(0x937) << uint32(0x0); // 26 2359 - data << uint32(0x938) << uint32(0x0); // 27 2360 - data << uint32(0x939) << uint32(0x1); // 28 2361 - data << uint32(0x930) << uint32(0x1); // 29 2352 - data << uint32(0x93a) << uint32(0x0); // 30 2362 - data << uint32(0x93b) << uint32(0x0); // 31 2363 - data << uint32(0x93c) << uint32(0x0); // 32 2364 - data << uint32(0x93d) << uint32(0x0); // 33 2365 - data << uint32(0x944) << uint32(0x0); // 34 2372 - data << uint32(0x945) << uint32(0x0); // 35 2373 - data << uint32(0x931) << uint32(0x1); // 36 2353 - data << uint32(0x93e) << uint32(0x0); // 37 2366 - data << uint32(0x931) << uint32(0x1); // 38 2367 ?? grey horde not in dbc! send for consistency's sake, and to match field count - data << uint32(0x940) << uint32(0x0); // 39 2368 - data << uint32(0x941) << uint32(0x0); // 7 2369 - data << uint32(0x942) << uint32(0x0); // 8 2370 - data << uint32(0x943) << uint32(0x0); // 9 2371 - } - break; case 1377: // Silithus if (pvp && pvp->GetTypeId() == OUTDOOR_PVP_SI) pvp->FillInitialWorldStates(data); @@ -9665,16 +9804,37 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(4131) << uint32(0); // 10 WORLDSTATE_ALGALON_DESPAWN_TIMER } break; - // Halls of Refection - case 4820: - if (instance && mapid == 668) + // Zul Aman + case 3805: + if (instance && mapid == 568) instance->FillInitialWorldStates(data); else { - data << uint32(4884) << uint32(0); // 9 WORLD_STATE_HOR_WAVES_ENABLED - data << uint32(4882) << uint32(0); // 10 WORLD_STATE_HOR_WAVE_COUNT + data << uint32(3104) << uint32(0); // 9 WORLD_STATE_ZULAMAN_TIMER_ENABLED + data << uint32(3106) << uint32(0); // 10 WORLD_STATE_ZULAMAN_TIMER + } + break; + // Twin Peaks + case 5031: + if (bg && bg->GetTypeID(true) == BATTLEGROUND_TP) + bg->FillInitialWorldStates(data); + else + { + data << uint32(0x62d) << uint32(0x0); // 7 1581 alliance flag captures + data << uint32(0x62e) << uint32(0x0); // 8 1582 horde flag captures + data << uint32(0x609) << uint32(0x0); // 9 1545 unk + data << uint32(0x60a) << uint32(0x0); // 10 1546 unk + data << uint32(0x60b) << uint32(0x2); // 11 1547 unk + data << uint32(0x641) << uint32(0x3); // 12 1601 unk + data << uint32(0x922) << uint32(0x1); // 13 2338 horde (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing) + data << uint32(0x923) << uint32(0x1); // 14 2339 alliance (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing) } break; + // Battle for Gilneas + case 5449: + if (bg && bg->GetTypeID(true) == BATTLEGROUND_BFG) + bg->FillInitialWorldStates(data); + break; // Wintergrasp case 4197: if (bf && bf->GetTypeId() == BATTLEFIELD_WG) @@ -9682,6 +9842,16 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) bf->FillInitialWorldStates(data); break; } + // Halls of Refection + case 4820: + if (instance && mapid == 668) + instance->FillInitialWorldStates(data); + else + { + data << uint32(4884) << uint32(0); // 9 WORLD_STATE_HOR_WAVES_ENABLED + data << uint32(4882) << uint32(0); // 10 WORLD_STATE_HOR_WAVE_COUNT + } + break; // No break here, intended. default: data << uint32(0x914) << uint32(0x0); // 7 @@ -9719,7 +9889,7 @@ void Player::SendBattlefieldWorldStates() /// Send misc stuff that needs to be sent on every login, like the battle timers. if (sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE)) { - if (BattlefieldWG* wg = (BattlefieldWG*)sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG)) + if (Battlefield* wg = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG)) { if (wg->IsWarTime()) SendUpdateWorldState(ClockWorldState[1], uint32(time(NULL))); @@ -9754,9 +9924,9 @@ void Player::SetBindPoint(uint64 guid) void Player::SendTalentWipeConfirm(uint64 guid) { - WorldPacket data(MSG_TALENT_WIPE_CONFIRM, (8+4)); + WorldPacket data(MSG_TALENT_WIPE_CONFIRM, 8 + 4); data << uint64(guid); - uint32 cost = sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST) ? 0 : ResetTalentsCost(); + uint32 cost = sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST) ? 0 : GetNextResetTalentsCost(); data << cost; GetSession()->SendPacket(&data); } @@ -9954,30 +10124,10 @@ uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) c break; case INVTYPE_RELIC: { - switch (proto->SubClass) - { - case ITEM_SUBCLASS_ARMOR_LIBRAM: - if (playerClass == CLASS_PALADIN) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case ITEM_SUBCLASS_ARMOR_IDOL: - if (playerClass == CLASS_DRUID) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case ITEM_SUBCLASS_ARMOR_TOTEM: - if (playerClass == CLASS_SHAMAN) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case ITEM_SUBCLASS_ARMOR_MISC: - if (playerClass == CLASS_WARLOCK) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - case ITEM_SUBCLASS_ARMOR_SIGIL: - if (playerClass == CLASS_DEATH_KNIGHT) - slots[0] = EQUIPMENT_SLOT_RANGED; - break; - } - break; + if (playerClass == CLASS_PALADIN || playerClass == CLASS_DRUID || + playerClass == CLASS_SHAMAN || playerClass == CLASS_DEATH_KNIGHT) + slots[0] = EQUIPMENT_SLOT_RANGED; + break; } default: return NULL_SLOT; @@ -10039,14 +10189,6 @@ InventoryResult Player::CanUnequipItems(uint32 item, uint32 count) const return EQUIP_ERR_OK; } - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (pItem->GetEntry() == item) - { - tempcount += pItem->GetCount(); - if (tempcount >= count) - return EQUIP_ERR_OK; - } for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) if (Bag* pBag = GetBagByPos(i)) @@ -10071,11 +10213,6 @@ uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const if (pItem != skipItem && pItem->GetEntry() == item) count += pItem->GetCount(); - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (pItem != skipItem && pItem->GetEntry() == item) - count += pItem->GetCount(); - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) if (Bag* pBag = GetBagByPos(i)) count += pBag->GetItemCount(item, skipItem); @@ -10118,13 +10255,6 @@ uint32 Player::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipIte if (pProto->ItemLimitCategory == limitCategory) count += pItem->GetCount(); - for (int i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (pItem != skipItem) - if (ItemTemplate const* pProto = pItem->GetTemplate()) - if (pProto->ItemLimitCategory == limitCategory) - count += pItem->GetCount(); - for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) if (Bag* pBag = GetBagByPos(i)) count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem); @@ -10150,11 +10280,6 @@ Item* Player::GetItemByGuid(uint64 guid) const if (pItem->GetGUID() == guid) return pItem; - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (pItem->GetGUID() == guid) - return pItem; - for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) if (pItem->GetGUID() == guid) @@ -10186,7 +10311,7 @@ Item* Player::GetItemByPos(uint16 pos) const Item* Player::GetItemByPos(uint8 bag, uint8 slot) const { - if (bag == INVENTORY_SLOT_BAG_0 && (slot < BANK_SLOT_BAG_END || (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END))) + if (bag == INVENTORY_SLOT_BAG_0 && slot < BANK_SLOT_BAG_END) return m_items[slot]; else if (Bag* pBag = GetBagByPos(bag)) return pBag->GetItemByPos(slot); @@ -10276,8 +10401,6 @@ bool Player::IsInventoryPos(uint8 bag, uint8 slot) return true; if (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) return true; - if (bag == INVENTORY_SLOT_BAG_0 && (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END)) - return true; return false; } @@ -10336,10 +10459,6 @@ bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) if (slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END) return true; - // keyring slots - if (slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END) - return true; - // bank main slots if (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END) return true; @@ -10379,16 +10498,7 @@ bool Player::HasItemCount(uint32 item, uint32 count, bool inBankAlso) const return true; } } - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - { - Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade()) - { - tempcount += pItem->GetCount(); - if (tempcount >= count) - return true; - } - } + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { if (Bag* pBag = GetBagByPos(i)) @@ -10518,11 +10628,11 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item { if (no_space_count) *no_space_count = count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } if (pItem && pItem->m_lootGenerated) - return EQUIP_ERR_ALREADY_LOOTED; + return EQUIP_ERR_LOOT_GONE; // no maximum if ((pProto->MaxCount <= 0 && pProto->ItemLimitCategory == 0) || pProto->MaxCount == 2147483647) @@ -10535,7 +10645,7 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item { if (no_space_count) *no_space_count = count + curcount - pProto->MaxCount; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } @@ -10547,7 +10657,7 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item { if (no_space_count) *no_space_count = count; - return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + return EQUIP_ERR_NOT_EQUIPPABLE; } if (limitEntry->mode == ITEM_LIMIT_CATEGORY_MODE_HAVE) @@ -10557,7 +10667,7 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item { if (no_space_count) *no_space_count = count + curcount - limitEntry->maxCount; - return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED; + return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS; } } } @@ -10578,36 +10688,6 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& des return CanStoreItem(bag, slot, dest, pItem->GetEntry(), count, pItem, swap, NULL); } -bool Player::HasItemTotemCategory(uint32 TotemCategory) const -{ - Item* pItem; - for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) - { - pItem = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i); - if (pItem && IsTotemCategoryCompatiableWith(pItem->GetTemplate()->TotemCategory, TotemCategory)) - return true; - } - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - { - pItem = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i); - if (pItem && IsTotemCategoryCompatiableWith(pItem->GetTemplate()->TotemCategory, TotemCategory)) - return true; - } - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) - { - if (Bag* pBag = GetBagByPos(i)) - { - for (uint32 j = 0; j < pBag->GetBagSize(); ++j) - { - pItem = GetUseableItemByPos(i, j); - if (pItem && IsTotemCategoryCompatiableWith(pItem->GetTemplate()->TotemCategory, TotemCategory)) - return true; - } - } - } - return false; -} - InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec &dest, ItemTemplate const* pProto, uint32& count, bool swap, Item* pSrcItem) const { Item* pItem2 = GetItemByPos(bag, slot); @@ -10619,40 +10699,32 @@ InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemP uint32 need_space; if (pSrcItem && pSrcItem->IsNotEmptyBag() && !IsBagPos(uint16(bag) << 8 | slot)) - return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS; + return EQUIP_ERR_DESTROY_NONEMPTY_BAG; // empty specific slot - check item fit to slot if (!pItem2 || swap) { if (bag == INVENTORY_SLOT_BAG_0) { - // keyring case - if (slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - - // currencytoken case - if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->IsCurrencyToken())) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - // prevent cheating if ((slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END) || slot >= PLAYER_SLOT_END) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; } else { Bag* pBag = GetBagByPos(bag); if (!pBag) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; ItemTemplate const* pBagProto = pBag->GetTemplate(); if (!pBagProto) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; if (slot >= pBagProto->ContainerSlots) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; if (!ItemCanGoIntoBag(pProto, pBagProto)) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; } // non empty stack with space @@ -10686,26 +10758,26 @@ InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, Ite { // skip specific bag already processed in first called CanStoreItem_InBag if (bag == skip_bag) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; // skip not existed bag or self targeted bag Bag* pBag = GetBagByPos(bag); if (!pBag || pBag == pSrcItem) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; if (pSrcItem && pSrcItem->IsNotEmptyBag()) - return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS; + return EQUIP_ERR_DESTROY_NONEMPTY_BAG; ItemTemplate const* pBagProto = pBag->GetTemplate(); if (!pBagProto) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; // specialized bag mode or non-specilized if (non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER)) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; if (!ItemCanGoIntoBag(pProto, pBagProto)) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; for (uint32 j = 0; j < pBag->GetBagSize(); j++) { @@ -10756,7 +10828,7 @@ InventoryResult Player::CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 sl { //this is never called for non-bag slots so we can do this if (pSrcItem && pSrcItem->IsNotEmptyBag()) - return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS; + return EQUIP_ERR_DESTROY_NONEMPTY_BAG; for (uint32 j = slot_begin; j < slot_end; j++) { @@ -10812,7 +10884,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des { if (no_space_count) *no_space_count = count; - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; + return swap ? EQUIP_ERR_CANT_SWAP : EQUIP_ERR_ITEM_NOT_FOUND; } if (pItem) @@ -10822,14 +10894,14 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des { if (no_space_count) *no_space_count = count; - return EQUIP_ERR_ALREADY_LOOTED; + return EQUIP_ERR_LOOT_GONE; } if (pItem->IsBindedNotWith(this)) { if (no_space_count) *no_space_count = count; - return EQUIP_ERR_DONT_OWN_THAT_ITEM; + return EQUIP_ERR_NOT_OWNER; } } @@ -10865,7 +10937,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } @@ -10879,24 +10951,6 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des { if (bag == INVENTORY_SLOT_BAG_0) // inventory { - res = CanStoreItem_InInventorySlots(KEYRING_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, true, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - { - if (no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if (count == 0) - { - if (no_similar_count == 0) - return EQUIP_ERR_OK; - - if (no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot); if (res != EQUIP_ERR_OK) { @@ -10912,7 +10966,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } else // equipped bag @@ -10936,7 +10990,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } } @@ -10944,67 +10998,6 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des // search free slot in bag for place to if (bag == INVENTORY_SLOT_BAG_0) // inventory { - // search free slot - keyring case - if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS) - { - uint32 keyringSize = GetMaxKeyringSize(); - res = CanStoreItem_InInventorySlots(KEYRING_SLOT_START, KEYRING_SLOT_START+keyringSize, dest, pProto, count, false, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - { - if (no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if (count == 0) - { - if (no_similar_count == 0) - return EQUIP_ERR_OK; - - if (no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - - res = CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, false, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - { - if (no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if (count == 0) - { - if (no_similar_count == 0) - return EQUIP_ERR_OK; - - if (no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - else if (pProto->IsCurrencyToken()) - { - res = CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, false, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - { - if (no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if (count == 0) - { - if (no_similar_count == 0) - return EQUIP_ERR_OK; - - if (no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot); if (res != EQUIP_ERR_OK) { @@ -11020,7 +11013,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } else // equipped bag @@ -11043,7 +11036,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } } @@ -11053,24 +11046,6 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des // search stack for merge to if (pProto->Stackable != 1) { - res = CanStoreItem_InInventorySlots(KEYRING_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, true, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - { - if (no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if (count == 0) - { - if (no_similar_count == 0) - return EQUIP_ERR_OK; - - if (no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot); if (res != EQUIP_ERR_OK) { @@ -11086,7 +11061,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } if (pProto->BagFamily) @@ -11104,7 +11079,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } } @@ -11122,7 +11097,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } } @@ -11130,48 +11105,6 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des // search free slot - special bag case if (pProto->BagFamily) { - if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS) - { - uint32 keyringSize = GetMaxKeyringSize(); - res = CanStoreItem_InInventorySlots(KEYRING_SLOT_START, KEYRING_SLOT_START+keyringSize, dest, pProto, count, false, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - { - if (no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if (count == 0) - { - if (no_similar_count == 0) - return EQUIP_ERR_OK; - - if (no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - else if (pProto->IsCurrencyToken()) - { - res = CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, false, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - { - if (no_space_count) - *no_space_count = count + no_similar_count; - return res; - } - - if (count == 0) - { - if (no_similar_count == 0) - return EQUIP_ERR_OK; - - if (no_space_count) - *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; - } - } - for (uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { res = CanStoreItem_InBag(i, dest, pProto, count, false, false, pItem, bag, slot); @@ -11185,13 +11118,13 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } } if (pItem && pItem->IsNotEmptyBag()) - return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG; + return EQUIP_ERR_BAG_IN_BAG; // search free slot res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot); @@ -11209,7 +11142,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) @@ -11225,14 +11158,14 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + return EQUIP_ERR_ITEM_MAX_COUNT; } } if (no_space_count) *no_space_count = count + no_similar_count; - return EQUIP_ERR_INVENTORY_FULL; + return EQUIP_ERR_INV_FULL; } ////////////////////////////////////////////////////////////////////////// @@ -11243,13 +11176,9 @@ InventoryResult Player::CanStoreItems(Item** pItems, int count) const // fill space table int inv_slot_items[INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START]; int inv_bags[INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE]; - int inv_keys[KEYRING_SLOT_END - KEYRING_SLOT_START]; - int inv_tokens[CURRENCYTOKEN_SLOT_END - CURRENCYTOKEN_SLOT_START]; memset(inv_slot_items, 0, sizeof(int) * (INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START)); memset(inv_bags, 0, sizeof(int) * (INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START) * MAX_BAG_SIZE); - memset(inv_keys, 0, sizeof(int) * (KEYRING_SLOT_END - KEYRING_SLOT_START)); - memset(inv_tokens, 0, sizeof(int) * (CURRENCYTOKEN_SLOT_END - CURRENCYTOKEN_SLOT_START)); for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) { @@ -11258,20 +11187,6 @@ InventoryResult Player::CanStoreItems(Item** pItems, int count) const inv_slot_items[i - INVENTORY_SLOT_ITEM_START] = pItem2->GetCount(); } - for (uint8 i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) - { - pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (pItem2 && !pItem2->IsInTrade()) - inv_keys[i - KEYRING_SLOT_START] = pItem2->GetCount(); - } - - for (uint8 i = CURRENCYTOKEN_SLOT_START; i < CURRENCYTOKEN_SLOT_END; i++) - { - pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (pItem2 && !pItem2->IsInTrade()) - inv_tokens[i - CURRENCYTOKEN_SLOT_START] = pItem2->GetCount(); - } - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) if (Bag* pBag = GetBagByPos(i)) for (uint32 j = 0; j < pBag->GetBagSize(); j++) @@ -11299,11 +11214,11 @@ InventoryResult Player::CanStoreItems(Item** pItems, int count) const // item used if (pItem->m_lootGenerated) - return EQUIP_ERR_ALREADY_LOOTED; + return EQUIP_ERR_LOOT_GONE; // item it 'bind' if (pItem->IsBindedNotWith(this)) - return EQUIP_ERR_DONT_OWN_THAT_ITEM; + return EQUIP_ERR_NOT_OWNER; ItemTemplate const* pBagProto; @@ -11317,32 +11232,6 @@ InventoryResult Player::CanStoreItems(Item** pItems, int count) const { bool b_found = false; - for (uint8 t = KEYRING_SLOT_START; t < KEYRING_SLOT_END; ++t) - { - pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t); - if (pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_keys[t-KEYRING_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) - { - inv_keys[t-KEYRING_SLOT_START] += pItem->GetCount(); - b_found = true; - break; - } - } - if (b_found) - continue; - - for (int t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; ++t) - { - pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t); - if (pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_tokens[t-CURRENCYTOKEN_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) - { - inv_tokens[t-CURRENCYTOKEN_SLOT_START] += pItem->GetCount(); - b_found = true; - break; - } - } - if (b_found) - continue; - for (int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; ++t) { pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t); @@ -11383,38 +11272,6 @@ InventoryResult Player::CanStoreItems(Item** pItems, int count) const if (pProto->BagFamily) { bool b_found = false; - if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS) - { - uint32 keyringSize = GetMaxKeyringSize(); - for (uint32 t = KEYRING_SLOT_START; t < KEYRING_SLOT_START+keyringSize; ++t) - { - if (inv_keys[t-KEYRING_SLOT_START] == 0) - { - inv_keys[t-KEYRING_SLOT_START] = 1; - b_found = true; - break; - } - } - } - - if (b_found) - continue; - - if (pProto->IsCurrencyToken()) - { - for (uint32 t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; ++t) - { - if (inv_tokens[t-CURRENCYTOKEN_SLOT_START] == 0) - { - inv_tokens[t-CURRENCYTOKEN_SLOT_START] = 1; - b_found = true; - break; - } - } - } - - if (b_found) - continue; for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t) { @@ -11481,7 +11338,7 @@ InventoryResult Player::CanStoreItems(Item** pItems, int count) const // no free slot found? if (!b_found) - return EQUIP_ERR_INVENTORY_FULL; + return EQUIP_ERR_INV_FULL; } return EQUIP_ERR_OK; @@ -11513,10 +11370,10 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool { // item used if (pItem->m_lootGenerated) - return EQUIP_ERR_ALREADY_LOOTED; + return EQUIP_ERR_LOOT_GONE; if (pItem->IsBindedNotWith(this)) - return EQUIP_ERR_DONT_OWN_THAT_ITEM; + return EQUIP_ERR_NOT_OWNER; // check count of items (skip for auto move for same player from bank) InventoryResult res = CanTakeMoreSimilarItems(pItem); @@ -11529,7 +11386,7 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool // May be here should be more stronger checks; STUNNED checked // ROOT, CONFUSED, DISTRACTED, FLEEING this needs to be checked. if (HasUnitState(UNIT_STATE_STUNNED)) - return EQUIP_ERR_YOU_ARE_STUNNED; + return EQUIP_ERR_GENERIC_STUNNED; // do not allow equipping gear except weapons, offhands, projectiles, relics in // - combat @@ -11545,27 +11402,27 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool } if (IsInCombat()&& (pProto->Class == ITEM_CLASS_WEAPON || pProto->InventoryType == INVTYPE_RELIC) && m_weaponChangeTimer != 0) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err + return EQUIP_ERR_CLIENT_LOCKED_OUT; // maybe exist better err if (IsNonMeleeSpellCast(false)) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; + return EQUIP_ERR_CLIENT_LOCKED_OUT; } ScalingStatDistributionEntry const* ssd = pProto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(pProto->ScalingStatDistribution) : 0; // check allowed level (extend range to upper values if MaxLevel more or equal max player level, this let GM set high level with 1...max range items) if (ssd && ssd->MaxLevel < DEFAULT_MAX_LEVEL && ssd->MaxLevel < getLevel()) - return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + return EQUIP_ERR_NOT_EQUIPPABLE; uint8 eslot = FindEquipSlot(pProto, slot, swap); if (eslot == NULL_SLOT) - return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + return EQUIP_ERR_NOT_EQUIPPABLE; res = CanUseItem(pItem, not_loading); if (res != EQUIP_ERR_OK) return res; if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot)) - return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE; + return EQUIP_ERR_NO_SLOT_AVAILABLE; // if we are swapping 2 equiped items, CanEquipUniqueItem check // should ignore the item we are trying to swap, and not the @@ -11609,8 +11466,8 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool if (ItemTemplate const* pBagProto = pBag->GetTemplate()) if (pBagProto->Class == pProto->Class && (!swap || pBag->GetSlot() != eslot)) return (pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH) - ? EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH - : EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER; + ? EQUIP_ERR_ONLY_ONE_AMMO + : EQUIP_ERR_ONLY_ONE_QUIVER; uint32 type = pProto->InventoryType; @@ -11618,21 +11475,20 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool { // Do not allow polearm to be equipped in the offhand (rare case for the only 1h polearm 41750) if (type == INVTYPE_WEAPON && pProto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM) - return EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT; - + return EQUIP_ERR_2HSKILLNOTFOUND; else if (type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND) { if (!CanDualWield()) - return EQUIP_ERR_CANT_DUAL_WIELD; + return EQUIP_ERR_2HSKILLNOTFOUND; } else if (type == INVTYPE_2HWEAPON) { if (!CanDualWield() || !CanTitanGrip()) - return EQUIP_ERR_CANT_DUAL_WIELD; + return EQUIP_ERR_2HSKILLNOTFOUND; } if (IsTwoHandUsed()) - return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED; + return EQUIP_ERR_2HANDED_EQUIPPED; } // equip two-hand weapon case (with possible unequip 2 items) @@ -11641,10 +11497,10 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool if (eslot == EQUIPMENT_SLOT_OFFHAND) { if (!CanTitanGrip()) - return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + return EQUIP_ERR_NOT_EQUIPPABLE; } else if (eslot != EQUIPMENT_SLOT_MAINHAND) - return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + return EQUIP_ERR_NOT_EQUIPPABLE; if (!CanTitanGrip()) { @@ -11654,7 +11510,7 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool if (offItem && (!not_loading || CanUnequipItem(uint16(INVENTORY_SLOT_BAG_0) << 8 | EQUIPMENT_SLOT_OFFHAND, false) != EQUIP_ERR_OK || CanStoreItem(NULL_BAG, NULL_SLOT, off_dest, offItem, false) != EQUIP_ERR_OK)) - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_INVENTORY_FULL; + return swap ? EQUIP_ERR_CANT_SWAP : EQUIP_ERR_INV_FULL; } } dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot); @@ -11662,7 +11518,7 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool } } - return !swap ? EQUIP_ERR_ITEM_NOT_FOUND : EQUIP_ERR_ITEMS_CANT_BE_SWAPPED; + return !swap ? EQUIP_ERR_ITEM_NOT_FOUND : EQUIP_ERR_CANT_SWAP; } InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const @@ -11685,7 +11541,7 @@ InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const // item used if (pItem->m_lootGenerated) - return EQUIP_ERR_ALREADY_LOOTED; + return EQUIP_ERR_LOOT_GONE; // do not allow unequipping gear except weapons, offhands, projectiles, relics in // - combat @@ -11701,7 +11557,7 @@ InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const } if (!swap && pItem->IsNotEmptyBag()) - return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS; + return EQUIP_ERR_DESTROY_NONEMPTY_BAG; return EQUIP_ERR_OK; } @@ -11709,29 +11565,28 @@ InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item* pItem, bool swap, bool not_loading) const { if (!pItem) - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; + return swap ? EQUIP_ERR_CANT_SWAP : EQUIP_ERR_ITEM_NOT_FOUND; uint32 count = pItem->GetCount(); TC_LOG_DEBUG("entities.player.items", "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount()); ItemTemplate const* pProto = pItem->GetTemplate(); if (!pProto) - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; + return swap ? EQUIP_ERR_CANT_SWAP : EQUIP_ERR_ITEM_NOT_FOUND; // item used if (pItem->m_lootGenerated) - return EQUIP_ERR_ALREADY_LOOTED; + return EQUIP_ERR_LOOT_GONE; if (pItem->IsBindedNotWith(this)) - return EQUIP_ERR_DONT_OWN_THAT_ITEM; + return EQUIP_ERR_NOT_OWNER; - // Currency tokens are not supposed to be swapped out of their hidden bag - uint8 pItemslot = pItem->GetSlot(); - if (pItemslot >= CURRENCYTOKEN_SLOT_START && pItemslot < CURRENCYTOKEN_SLOT_END) + // Currency Tokenizer are not supposed to be swapped out of their hidden bag + if (pItem->IsCurrencyToken()) { TC_LOG_ERROR("entities.player", "Possible hacking attempt: Player %s [guid: %u] tried to move token [guid: %u, entry: %u] out of the currency bag!", GetName().c_str(), GetGUIDLow(), pItem->GetGUIDLow(), pProto->ItemId); - return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED; + return EQUIP_ERR_CANT_SWAP; } // check count of items (skip for auto move for same player from bank) @@ -11745,10 +11600,10 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END) { if (!pItem->IsBag()) - return EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT; + return EQUIP_ERR_WRONG_SLOT; if (slot - BANK_SLOT_BAG_START >= GetBankBagSlotCount()) - return EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT; + return EQUIP_ERR_NO_BANK_SLOT; res = CanUseItem(pItem, not_loading); if (res != EQUIP_ERR_OK) @@ -11769,7 +11624,7 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest if (bag != NULL_BAG) { if (pItem->IsNotEmptyBag()) - return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG; + return EQUIP_ERR_BAG_IN_BAG; // search stack in bag for merge to if (pProto->Stackable != 1) @@ -11900,16 +11755,16 @@ InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const TC_LOG_DEBUG("entities.player.items", "STORAGE: CanUseItem item = %u", pItem->GetEntry()); if (!IsAlive() && not_loading) - return EQUIP_ERR_YOU_ARE_DEAD; + return EQUIP_ERR_PLAYER_DEAD; //if (isStunned()) - // return EQUIP_ERR_YOU_ARE_STUNNED; + // return EQUIP_ERR_GENERIC_STUNNED; ItemTemplate const* pProto = pItem->GetTemplate(); if (pProto) { if (pItem->IsBindedNotWith(this)) - return EQUIP_ERR_DONT_OWN_THAT_ITEM; + return EQUIP_ERR_NOT_OWNER; InventoryResult res = CanUseItem(pProto); if (res != EQUIP_ERR_OK) @@ -11922,8 +11777,7 @@ InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const // Armor that is binded to account can "morph" from plate to mail, etc. if skill is not learned yet. if (pProto->Quality == ITEM_QUALITY_HEIRLOOM && pProto->Class == ITEM_CLASS_ARMOR && !HasSkill(itemSkill)) { - /// @todo when you right-click already equipped item it throws EQUIP_ERR_NO_REQUIRED_PROFICIENCY. - + /// @todo when you right-click already equipped item it throws EQUIP_ERR_PROFICIENCY_NEEDED. // In fact it's a visual bug, everything works properly... I need sniffs of operations with // binded to account items from off server. @@ -11940,7 +11794,7 @@ InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const } } if (!allowEquip && GetSkillValue(itemSkill) == 0) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + return EQUIP_ERR_PROFICIENCY_NEEDED; } if (pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank) @@ -11959,31 +11813,31 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const if (proto) { if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && GetTeam() != HORDE) - return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + return EQUIP_ERR_CANT_EQUIP_EVER; if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && GetTeam() != ALLIANCE) - return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + return EQUIP_ERR_CANT_EQUIP_EVER; if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0) - return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + return EQUIP_ERR_CANT_EQUIP_EVER; if (proto->RequiredSkill != 0) { if (GetSkillValue(proto->RequiredSkill) == 0) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + return EQUIP_ERR_PROFICIENCY_NEEDED; else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank) return EQUIP_ERR_CANT_EQUIP_SKILL; } if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell)) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + return EQUIP_ERR_PROFICIENCY_NEEDED; if (getLevel() < proto->RequiredLevel) return EQUIP_ERR_CANT_EQUIP_LEVEL_I; // If World Event is not active, prevent using event dependant items if (proto->HolidayId && !IsHolidayActive((HolidayIds)proto->HolidayId)) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; + return EQUIP_ERR_CLIENT_LOCKED_OUT; return EQUIP_ERR_OK; } @@ -12015,15 +11869,15 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje }; //Copy from function Item::GetSkill() if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0) - return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + return EQUIP_ERR_CANT_EQUIP_EVER; if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell)) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + return EQUIP_ERR_PROFICIENCY_NEEDED; if (proto->RequiredSkill != 0) { if (!GetSkillValue(proto->RequiredSkill)) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + return EQUIP_ERR_PROFICIENCY_NEEDED; else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank) return EQUIP_ERR_CANT_EQUIP_SKILL; } @@ -12031,108 +11885,43 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje uint8 _class = getClass(); if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + return EQUIP_ERR_PROFICIENCY_NEEDED; - if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass > ITEM_SUBCLASS_ARMOR_MISC && proto->SubClass < ITEM_SUBCLASS_ARMOR_BUCKLER && proto->InventoryType != INVTYPE_CLOAK) + if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass > ITEM_SUBCLASS_ARMOR_MISCELLANEOUS && proto->SubClass < ITEM_SUBCLASS_ARMOR_BUCKLER && proto->InventoryType != INVTYPE_CLOAK) { if (_class == CLASS_WARRIOR || _class == CLASS_PALADIN || _class == CLASS_DEATH_KNIGHT) { if (getLevel() < 40) { if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; + return EQUIP_ERR_CLIENT_LOCKED_OUT; } else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_PLATE) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; + return EQUIP_ERR_CLIENT_LOCKED_OUT; } else if (_class == CLASS_HUNTER || _class == CLASS_SHAMAN) { if (getLevel() < 40) { if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; + return EQUIP_ERR_CLIENT_LOCKED_OUT; } else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; + return EQUIP_ERR_CLIENT_LOCKED_OUT; } if (_class == CLASS_ROGUE || _class == CLASS_DRUID) if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; + return EQUIP_ERR_CLIENT_LOCKED_OUT; if (_class == CLASS_MAGE || _class == CLASS_PRIEST || _class == CLASS_WARLOCK) if (proto->SubClass != ITEM_SUBCLASS_ARMOR_CLOTH) - return EQUIP_ERR_CANT_DO_RIGHT_NOW; + return EQUIP_ERR_CLIENT_LOCKED_OUT; } return EQUIP_ERR_OK; } -InventoryResult Player::CanUseAmmo(uint32 item) const -{ - TC_LOG_DEBUG("entities.player.items", "STORAGE: CanUseAmmo item = %u", item); - if (!IsAlive()) - return EQUIP_ERR_YOU_ARE_DEAD; - //if (isStunned()) - // return EQUIP_ERR_YOU_ARE_STUNNED; - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item); - if (pProto) - { - if (pProto->InventoryType!= INVTYPE_AMMO) - return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE; - - InventoryResult res = CanUseItem(pProto); - if (res != EQUIP_ERR_OK) - return res; - - /*if (GetReputationMgr().GetReputation() < pProto->RequiredReputation) - return EQUIP_ERR_CANT_EQUIP_REPUTATION; - */ - - // Requires No Ammo - if (HasAura(46699)) - return EQUIP_ERR_BAG_FULL6; - - return EQUIP_ERR_OK; - } - return EQUIP_ERR_ITEM_NOT_FOUND; -} - -void Player::SetAmmo(uint32 item) -{ - if (!item) - return; - - // already set - if (GetUInt32Value(PLAYER_AMMO_ID) == item) - return; - - // check ammo - if (item) - { - InventoryResult msg = CanUseAmmo(item); - if (msg != EQUIP_ERR_OK) - { - SendEquipError(msg, NULL, NULL, item); - return; - } - } - - SetUInt32Value(PLAYER_AMMO_ID, item); - - _ApplyAmmoBonuses(); -} - -void Player::RemoveAmmo() -{ - SetUInt32Value(PLAYER_AMMO_ID, 0); - - m_ammoDPS = 0.0f; - - if (CanModifyStats()) - UpdateDamagePhysical(RANGED_ATTACK); -} - // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update, int32 randomPropertyId, AllowedLooterSet const& allowedLooters) { @@ -12234,10 +12023,6 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool pItem->SetSlot(slot); pItem->SetContainer(NULL); - - // need update known currency - if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END) - AddKnownCurrency(pItem->GetEntry()); } else pBag->StoreItem(slot, pItem, update); @@ -12452,7 +12237,7 @@ void Player::SetVisibleItemSlot(uint8 slot, Item* pItem) { if (pItem) { - SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry()); + SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetVisibleEntry()); SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 1, pItem->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); } @@ -12751,34 +12536,6 @@ void Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, bool } } - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - { - if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - { - if (item->GetEntry() == itemEntry && !item->IsInTrade()) - { - if (item->GetCount() + remcount <= count) - { - // all keys can be unequipped - remcount += item->GetCount(); - DestroyItem(INVENTORY_SLOT_BAG_0, i, update); - - if (remcount >= count) - return; - } - else - { - ItemRemovedQuestCheck(item->GetEntry(), count - remcount); - item->SetCount(item->GetCount() - count + remcount); - if (IsInWorld() && update) - item->SendUpdateToPlayer(this); - item->SetState(ITEM_CHANGED, this); - return; - } - } - } - } - // in inventory bags for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { @@ -12918,11 +12675,6 @@ void Player::DestroyZoneLimitedItem(bool update, uint32 new_zone) if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(), new_zone)) DestroyItem(INVENTORY_SLOT_BAG_0, i, update); - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(), new_zone)) - DestroyItem(INVENTORY_SLOT_BAG_0, i, update); - // in inventory bags for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) if (Bag* pBag = GetBagByPos(i)) @@ -12973,11 +12725,6 @@ Item* Player::GetItemByEntry(uint32 entry) const if (pItem->GetEntry() == entry) return pItem; - for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (pItem->GetEntry() == entry) - return pItem; - for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) if (Bag* pBag = GetBagByPos(i)) for (uint32 j = 0; j < pBag->GetBagSize(); ++j) @@ -13035,21 +12782,21 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) if (pSrcItem->m_lootGenerated) // prevent split looting item (item { //best error message found for attempting to split while looting - SendEquipError(EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_SPLIT_FAILED, pSrcItem, NULL); return; } // not let split all items (can be only at cheating) if (pSrcItem->GetCount() == count) { - SendEquipError(EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_SPLIT_FAILED, pSrcItem, NULL); return; } // not let split more existed items (can be only at cheating) if (pSrcItem->GetCount() < count) { - SendEquipError(EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_TOO_FEW_TO_SPLIT, pSrcItem, NULL); return; } @@ -13150,7 +12897,7 @@ void Player::SwapItem(uint16 src, uint16 dst) if (!IsAlive()) { - SendEquipError(EQUIP_ERR_YOU_ARE_DEAD, pSrcItem, pDstItem); + SendEquipError(EQUIP_ERR_PLAYER_DEAD, pSrcItem, pDstItem); return; } @@ -13159,7 +12906,7 @@ void Player::SwapItem(uint16 src, uint16 dst) if (pSrcItem->m_lootGenerated) // prevent swap looting item { //best error message found for attempting to swap while looting - SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, pSrcItem, NULL); + SendEquipError(EQUIP_ERR_CLIENT_LOCKED_OUT, pSrcItem, NULL); return; } @@ -13178,14 +12925,14 @@ void Player::SwapItem(uint16 src, uint16 dst) // prevent put equipped/bank bag in self if (IsBagPos(src) && srcslot == dstbag) { - SendEquipError(EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem); + SendEquipError(EQUIP_ERR_BAG_IN_BAG, pSrcItem, pDstItem); return; } // prevent equipping bag in the same slot from its inside if (IsBagPos(dst) && srcbag == dstslot) { - SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pSrcItem, pDstItem); + SendEquipError(EQUIP_ERR_CANT_SWAP, pSrcItem, pDstItem); return; } @@ -13196,7 +12943,7 @@ void Player::SwapItem(uint16 src, uint16 dst) if (pDstItem->m_lootGenerated) // prevent swap looting item { //best error message found for attempting to swap while looting - SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, pDstItem, NULL); + SendEquipError(EQUIP_ERR_CLIENT_LOCKED_OUT, pDstItem, NULL); return; } @@ -13393,7 +13140,7 @@ void Player::SwapItem(uint16 src, uint16 dst) if (!bagItemProto || !ItemCanGoIntoBag(bagItemProto, emptyProto)) { // one from items not go to empty target bag - SendEquipError(EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem); + SendEquipError(EQUIP_ERR_BAG_IN_BAG, pSrcItem, pDstItem); return; } @@ -13403,7 +13150,7 @@ void Player::SwapItem(uint16 src, uint16 dst) if (count > emptyBag->GetBagSize()) { // too small targeted bag - SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pSrcItem, pDstItem); + SendEquipError(EQUIP_ERR_CANT_SWAP, pSrcItem, pDstItem); return; } @@ -13597,16 +13344,16 @@ void Player::SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2, uint data << uint32(proto ? proto->RequiredLevel : 0); break; } - case EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM: // no idea about this one... + case EQUIP_ERR_NO_OUTPUT: // no idea about this one... { data << uint64(0); // item guid data << uint32(0); // slot data << uint64(0); // container break; } - case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED: - case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED: - case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED: + case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS: + case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED_IS: + case EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS: { ItemTemplate const* proto = pItem ? pItem->GetTemplate() : sObjectMgr->GetItemTemplate(itemid); data << uint32(proto ? proto->ItemLimitCategory : 0); @@ -13619,26 +13366,22 @@ void Player::SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2, uint GetSession()->SendPacket(&data); } -void Player::SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 param) +void Player::SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 /*param*/) { TC_LOG_DEBUG("network", "WORLD: Sent SMSG_BUY_FAILED"); WorldPacket data(SMSG_BUY_FAILED, (8+4+4+1)); data << uint64(creature ? creature->GetGUID() : 0); data << uint32(item); - if (param > 0) - data << uint32(param); data << uint8(msg); GetSession()->SendPacket(&data); } -void Player::SendSellError(SellResult msg, Creature* creature, uint64 guid, uint32 param) +void Player::SendSellError(SellResult msg, Creature* creature, uint64 guid) { TC_LOG_DEBUG("network", "WORLD: Sent SMSG_SELL_ITEM"); - WorldPacket data(SMSG_SELL_ITEM, (8+8+(param?4:0)+1)); // last check 2.0.10 + WorldPacket data(SMSG_SELL_ITEM, (8+8+1)); // last check 4.3.4 data << uint64(creature ? creature->GetGUID() : 0); data << uint64(guid); - if (param > 0) - data << uint32(param); data << uint8(msg); GetSession()->SendPacket(&data); } @@ -13754,6 +13497,9 @@ void Player::AddEnchantmentDurations(Item* item) { for (int x = 0; x < MAX_ENCHANTMENT_SLOT; ++x) { + if (x > PRISMATIC_ENCHANTMENT_SLOT && x < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id + continue; + if (!item->GetEnchantmentId(EnchantmentSlot(x))) continue; @@ -13848,10 +13594,257 @@ void Player::AddEnchantmentDuration(Item* item, EnchantmentSlot slot, uint32 dur } } +void Player::ApplyReforgeEnchantment(Item* item, bool apply) +{ + if (!item) + return; + + ItemReforgeEntry const* reforge = sItemReforgeStore.LookupEntry(item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)); + if (!reforge) + return; + + float removeValue = item->GetReforgableStat(ItemModType(reforge->SourceStat)) * reforge->SourceMultiplier; + float addValue = removeValue * reforge->FinalMultiplier; + + switch (reforge->SourceStat) + { + case ITEM_MOD_MANA: + HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, -removeValue, apply); + break; + case ITEM_MOD_HEALTH: + HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, -removeValue, apply); + break; + case ITEM_MOD_AGILITY: + HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, -removeValue, apply); + ApplyStatBuffMod(STAT_AGILITY, -removeValue, apply); + break; + case ITEM_MOD_STRENGTH: + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, -removeValue, apply); + ApplyStatBuffMod(STAT_STRENGTH, -removeValue, apply); + break; + case ITEM_MOD_INTELLECT: + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, -removeValue, apply); + ApplyStatBuffMod(STAT_INTELLECT, -removeValue, apply); + break; + case ITEM_MOD_SPIRIT: + HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, -removeValue, apply); + ApplyStatBuffMod(STAT_SPIRIT, -removeValue, apply); + break; + case ITEM_MOD_STAMINA: + HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, -removeValue, apply); + ApplyStatBuffMod(STAT_STAMINA, -removeValue, apply); + break; + case ITEM_MOD_DEFENSE_SKILL_RATING: + ApplyRatingMod(CR_DEFENSE_SKILL, -int32(removeValue), apply); + break; + case ITEM_MOD_DODGE_RATING: + ApplyRatingMod(CR_DODGE, -int32(removeValue), apply); + break; + case ITEM_MOD_PARRY_RATING: + ApplyRatingMod(CR_PARRY, -int32(removeValue), apply); + break; + case ITEM_MOD_BLOCK_RATING: + ApplyRatingMod(CR_BLOCK, -int32(removeValue), apply); + break; + case ITEM_MOD_HIT_MELEE_RATING: + ApplyRatingMod(CR_HIT_MELEE, -int32(removeValue), apply); + break; + case ITEM_MOD_HIT_RANGED_RATING: + ApplyRatingMod(CR_HIT_RANGED, -int32(removeValue), apply); + break; + case ITEM_MOD_HIT_SPELL_RATING: + ApplyRatingMod(CR_HIT_SPELL, -int32(removeValue), apply); + break; + case ITEM_MOD_CRIT_MELEE_RATING: + ApplyRatingMod(CR_CRIT_MELEE, -int32(removeValue), apply); + break; + case ITEM_MOD_CRIT_RANGED_RATING: + ApplyRatingMod(CR_CRIT_RANGED, -int32(removeValue), apply); + break; + case ITEM_MOD_CRIT_SPELL_RATING: + ApplyRatingMod(CR_CRIT_SPELL, -int32(removeValue), apply); + break; + case ITEM_MOD_HASTE_SPELL_RATING: + ApplyRatingMod(CR_HASTE_SPELL, -int32(removeValue), apply); + break; + case ITEM_MOD_HIT_RATING: + ApplyRatingMod(CR_HIT_MELEE, -int32(removeValue), apply); + ApplyRatingMod(CR_HIT_RANGED, -int32(removeValue), apply); + ApplyRatingMod(CR_HIT_SPELL, -int32(removeValue), apply); + break; + case ITEM_MOD_CRIT_RATING: + ApplyRatingMod(CR_CRIT_MELEE, -int32(removeValue), apply); + ApplyRatingMod(CR_CRIT_RANGED, -int32(removeValue), apply); + ApplyRatingMod(CR_CRIT_SPELL, -int32(removeValue), apply); + break; + case ITEM_MOD_RESILIENCE_RATING: + ApplyRatingMod(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN, -int32(removeValue), apply); + break; + case ITEM_MOD_HASTE_RATING: + ApplyRatingMod(CR_HASTE_MELEE, -int32(removeValue), apply); + ApplyRatingMod(CR_HASTE_RANGED, -int32(removeValue), apply); + ApplyRatingMod(CR_HASTE_SPELL, -int32(removeValue), apply); + break; + case ITEM_MOD_EXPERTISE_RATING: + ApplyRatingMod(CR_EXPERTISE, -int32(removeValue), apply); + break; + case ITEM_MOD_ATTACK_POWER: + HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, -removeValue, apply); + HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, -removeValue, apply); + break; + case ITEM_MOD_RANGED_ATTACK_POWER: + HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, -removeValue, apply); + break; + case ITEM_MOD_MANA_REGENERATION: + ApplyManaRegenBonus(-int32(removeValue), apply); + break; + case ITEM_MOD_ARMOR_PENETRATION_RATING: + ApplyRatingMod(CR_ARMOR_PENETRATION, -int32(removeValue), apply); + break; + case ITEM_MOD_SPELL_POWER: + ApplySpellPowerBonus(-int32(removeValue), apply); + break; + case ITEM_MOD_HEALTH_REGEN: + ApplyHealthRegenBonus(-int32(removeValue), apply); + break; + case ITEM_MOD_SPELL_PENETRATION: + ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, -int32(removeValue), apply); + m_spellPenetrationItemMod += apply ? -int32(removeValue) : int32(removeValue); + break; + case ITEM_MOD_BLOCK_VALUE: + HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, -removeValue, apply); + break; + case ITEM_MOD_MASTERY_RATING: + ApplyRatingMod(CR_MASTERY, -int32(removeValue), apply); + break; + } + + switch (reforge->FinalStat) + { + case ITEM_MOD_MANA: + HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, addValue, apply); + break; + case ITEM_MOD_HEALTH: + HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, addValue, apply); + break; + case ITEM_MOD_AGILITY: + HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, addValue, apply); + ApplyStatBuffMod(STAT_AGILITY, addValue, apply); + break; + case ITEM_MOD_STRENGTH: + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, addValue, apply); + ApplyStatBuffMod(STAT_STRENGTH, addValue, apply); + break; + case ITEM_MOD_INTELLECT: + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, addValue, apply); + ApplyStatBuffMod(STAT_INTELLECT, addValue, apply); + break; + case ITEM_MOD_SPIRIT: + HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, addValue, apply); + ApplyStatBuffMod(STAT_SPIRIT, addValue, apply); + break; + case ITEM_MOD_STAMINA: + HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, addValue, apply); + ApplyStatBuffMod(STAT_STAMINA, addValue, apply); + break; + case ITEM_MOD_DEFENSE_SKILL_RATING: + ApplyRatingMod(CR_DEFENSE_SKILL, int32(addValue), apply); + break; + case ITEM_MOD_DODGE_RATING: + ApplyRatingMod(CR_DODGE, int32(addValue), apply); + break; + case ITEM_MOD_PARRY_RATING: + ApplyRatingMod(CR_PARRY, int32(addValue), apply); + break; + case ITEM_MOD_BLOCK_RATING: + ApplyRatingMod(CR_BLOCK, int32(addValue), apply); + break; + case ITEM_MOD_HIT_MELEE_RATING: + ApplyRatingMod(CR_HIT_MELEE, int32(addValue), apply); + break; + case ITEM_MOD_HIT_RANGED_RATING: + ApplyRatingMod(CR_HIT_RANGED, int32(addValue), apply); + break; + case ITEM_MOD_HIT_SPELL_RATING: + ApplyRatingMod(CR_HIT_SPELL, int32(addValue), apply); + break; + case ITEM_MOD_CRIT_MELEE_RATING: + ApplyRatingMod(CR_CRIT_MELEE, int32(addValue), apply); + break; + case ITEM_MOD_CRIT_RANGED_RATING: + ApplyRatingMod(CR_CRIT_RANGED, int32(addValue), apply); + break; + case ITEM_MOD_CRIT_SPELL_RATING: + ApplyRatingMod(CR_CRIT_SPELL, int32(addValue), apply); + break; + case ITEM_MOD_HASTE_SPELL_RATING: + ApplyRatingMod(CR_HASTE_SPELL, int32(addValue), apply); + break; + case ITEM_MOD_HIT_RATING: + ApplyRatingMod(CR_HIT_MELEE, int32(addValue), apply); + ApplyRatingMod(CR_HIT_RANGED, int32(addValue), apply); + ApplyRatingMod(CR_HIT_SPELL, int32(addValue), apply); + break; + case ITEM_MOD_CRIT_RATING: + ApplyRatingMod(CR_CRIT_MELEE, int32(addValue), apply); + ApplyRatingMod(CR_CRIT_RANGED, int32(addValue), apply); + ApplyRatingMod(CR_CRIT_SPELL, int32(addValue), apply); + break; + case ITEM_MOD_RESILIENCE_RATING: + ApplyRatingMod(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN, int32(addValue), apply); + break; + case ITEM_MOD_HASTE_RATING: + ApplyRatingMod(CR_HASTE_MELEE, int32(addValue), apply); + ApplyRatingMod(CR_HASTE_RANGED, int32(addValue), apply); + ApplyRatingMod(CR_HASTE_SPELL, int32(addValue), apply); + break; + case ITEM_MOD_EXPERTISE_RATING: + ApplyRatingMod(CR_EXPERTISE, int32(addValue), apply); + break; + case ITEM_MOD_ATTACK_POWER: + HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, addValue, apply); + HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, addValue, apply); + break; + case ITEM_MOD_RANGED_ATTACK_POWER: + HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, addValue, apply); + break; + case ITEM_MOD_MANA_REGENERATION: + ApplyManaRegenBonus(int32(addValue), apply); + break; + case ITEM_MOD_ARMOR_PENETRATION_RATING: + ApplyRatingMod(CR_ARMOR_PENETRATION, int32(addValue), apply); + break; + case ITEM_MOD_SPELL_POWER: + ApplySpellPowerBonus(int32(addValue), apply); + break; + case ITEM_MOD_HEALTH_REGEN: + ApplyHealthRegenBonus(int32(addValue), apply); + break; + case ITEM_MOD_SPELL_PENETRATION: + ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, int32(addValue), apply); + m_spellPenetrationItemMod += apply ? int32(addValue) : -int32(addValue); + break; + case ITEM_MOD_BLOCK_VALUE: + HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, addValue, apply); + break; + case ITEM_MOD_MASTERY_RATING: + ApplyRatingMod(CR_MASTERY, int32(addValue), apply); + break; + } +} + void Player::ApplyEnchantment(Item* item, bool apply) { for (uint32 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) + { + // Apply reforge as last enchant + if (slot == REFORGE_ENCHANTMENT_SLOT) + continue; + ApplyEnchantment(item, EnchantmentSlot(slot), apply); + } + + ApplyEnchantment(item, REFORGE_ENCHANTMENT_SLOT, apply); } void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool apply_dur, bool ignore_condition) @@ -13862,6 +13855,15 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool if (slot >= MAX_ENCHANTMENT_SLOT) return; + if (slot == TRANSMOGRIFY_ENCHANTMENT_SLOT) + return; + + if (slot == REFORGE_ENCHANTMENT_SLOT) + { + ApplyReforgeEnchantment(item, apply); + return; + } + uint32 enchant_id = item->GetEnchantmentId(slot); if (!enchant_id) return; @@ -13879,6 +13881,11 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool if (pEnchant->requiredSkill > 0 && pEnchant->requiredSkillValue > GetSkillValue(pEnchant->requiredSkill)) return; + // Cogwheel gems dont have requirement data set in SpellItemEnchantment.dbc, but they do have it in Item-sparse.db2 + if (ItemTemplate const* gem = sObjectMgr->GetItemTemplate(pEnchant->GemID)) + if (gem->RequiredSkill && GetSkillValue(gem->RequiredSkill) < gem->RequiredSkillRank) + return; + // If we're dealing with a gem inside a prismatic socket we need to check the prismatic socket requirements // rather than the gem requirements itself. If the socket has no color it is a prismatic socket. if ((slot == SOCK_ENCHANTMENT_SLOT || slot == SOCK_ENCHANTMENT_SLOT_2 || slot == SOCK_ENCHANTMENT_SLOT_3) @@ -13920,13 +13927,13 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool { int32 basepoints = 0; // Random Property Exist - try found basepoints for spell (basepoints depends from item suffix factor) - if (item->GetItemRandomPropertyId()) + if (item->GetItemRandomPropertyId() < 0) { ItemRandomSuffixEntry const* item_rand = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); if (item_rand) { // Search enchant_amount - for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k) + for (int k = 0; k < 5; ++k) { if (item_rand->enchant_id[k] == enchant_id) { @@ -13972,7 +13979,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool ItemRandomSuffixEntry const* item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(item->GetItemRandomPropertyId())); if (item_rand_suffix) { - for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k) + for (int k = 0; k < 5; ++k) { if (item_rand_suffix->enchant_id[k] == enchant_id) { @@ -14059,32 +14066,32 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply); TC_LOG_DEBUG("entities.player.items", "+ %u SPELL_CRIT", enchant_amount); break; -// Values from ITEM_STAT_MELEE_HA_RATING to ITEM_MOD_HASTE_RANGED_RATING are never used -// in Enchantments -// case ITEM_MOD_HIT_TAKEN_MELEE_RATING: -// ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply); -// break; -// case ITEM_MOD_HIT_TAKEN_RANGED_RATING: -// ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply); -// break; -// case ITEM_MOD_HIT_TAKEN_SPELL_RATING: -// ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply); -// break; -// case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: -// ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); -// break; -// case ITEM_MOD_CRIT_TAKEN_RANGED_RATING: -// ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); -// break; -// case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: -// ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); -// break; -// case ITEM_MOD_HASTE_MELEE_RATING: -// ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply); -// break; -// case ITEM_MOD_HASTE_RANGED_RATING: -// ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply); -// break; + // Values from ITEM_STAT_MELEE_HA_RATING to ITEM_MOD_HASTE_RANGED_RATING are never used + // in Enchantments + // case ITEM_MOD_HIT_TAKEN_MELEE_RATING: + // ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply); + // break; + // case ITEM_MOD_HIT_TAKEN_RANGED_RATING: + // ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply); + // break; + // case ITEM_MOD_HIT_TAKEN_SPELL_RATING: + // ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply); + // break; + // case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: + // ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); + // break; + // case ITEM_MOD_CRIT_TAKEN_RANGED_RATING: + // ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); + // break; + // case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: + // ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); + // break; + // case ITEM_MOD_HASTE_MELEE_RATING: + // ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply); + // break; + // case ITEM_MOD_HASTE_RANGED_RATING: + // ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply); + // break; case ITEM_MOD_HASTE_SPELL_RATING: ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply); break; @@ -14100,21 +14107,18 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply); TC_LOG_DEBUG("entities.player.items", "+ %u CRITICAL", enchant_amount); break; -// Values ITEM_MOD_HIT_TAKEN_RATING and ITEM_MOD_CRIT_TAKEN_RATING are never used in Enchantment -// case ITEM_MOD_HIT_TAKEN_RATING: -// ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply); -// ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply); -// ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply); -// break; -// case ITEM_MOD_CRIT_TAKEN_RATING: -// ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); -// ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); -// ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); -// break; + // case ITEM_MOD_HIT_TAKEN_RATING: // Unused since 3.3.5 + // ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply); + // ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply); + // ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply); + // break; + // case ITEM_MOD_CRIT_TAKEN_RATING: // Unused since 3.3.5 + // ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); + // ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); + // ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); + // break; case ITEM_MOD_RESILIENCE_RATING: - ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply); - ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply); - ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply); + ApplyRatingMod(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN, enchant_amount, apply); TC_LOG_DEBUG("entities.player.items", "+ %u RESILIENCE", enchant_amount); break; case ITEM_MOD_HASTE_RATING: @@ -14136,10 +14140,6 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); TC_LOG_DEBUG("entities.player.items", "+ %u RANGED_ATTACK_POWER", enchant_amount); break; -// case ITEM_MOD_FERAL_ATTACK_POWER: -// ApplyFeralAPBonus(enchant_amount, apply); -// TC_LOG_DEBUG("entities.player.items", "+ %u FERAL_ATTACK_POWER", enchant_amount); -// break; case ITEM_MOD_MANA_REGENERATION: ApplyManaRegenBonus(enchant_amount, apply); TC_LOG_DEBUG("entities.player.items", "+ %u MANA_REGENERATION", enchant_amount); @@ -14164,8 +14164,10 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(enchant_amount), apply); TC_LOG_DEBUG("entities.player.items", "+ %u BLOCK_VALUE", enchant_amount); break; - case ITEM_MOD_SPELL_HEALING_DONE: // deprecated - case ITEM_MOD_SPELL_DAMAGE_DONE: // deprecated + case ITEM_MOD_MASTERY_RATING: + ApplyRatingMod(CR_MASTERY, enchant_amount, apply); + TC_LOG_DEBUG("entities.player.items", "+ %u MASTERY", enchant_amount); + break; default: break; } @@ -14234,6 +14236,9 @@ void Player::UpdateSkillEnchantments(uint16 skill_id, uint16 curr_value, uint16 { for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) { + if (slot > PRISMATIC_ENCHANTMENT_SLOT && slot < PROP_ENCHANTMENT_SLOT_0) // not holding enchantment id + continue; + uint32 ench_id = m_items[i]->GetEnchantmentId(EnchantmentSlot(slot)); if (!ench_id) continue; @@ -14274,17 +14279,13 @@ void Player::UpdateSkillEnchantments(uint16 skill_id, uint16 curr_value, uint16 void Player::SendEnchantmentDurations() { for (EnchantDurationList::const_iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end(); ++itr) - { GetSession()->SendItemEnchantTimeUpdate(GetGUID(), itr->item->GetGUID(), itr->slot, uint32(itr->leftduration) / 1000); - } } void Player::SendItemDurations() { for (ItemDurationList::const_iterator itr = m_itemDuration.begin(); itr != m_itemDuration.end(); ++itr) - { (*itr)->SendTimeUpdate(this); - } } void Player::SendNewItem(Item* item, uint32 count, bool received, bool created, bool broadcast) @@ -14540,7 +14541,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men return; int32 cost = int32(item->BoxMoney); - if (!HasEnoughMoney(cost)) + if (!HasEnoughMoney(int64(cost))) { SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0); PlayerTalkClass->SendCloseGossip(); @@ -14709,11 +14710,11 @@ void Player::PrepareQuestMenu(uint64 guid) //only for quests which cast teleport spells on player Map* _map = IsInWorld() ? GetMap() : sMapMgr->FindMap(GetMapId(), GetInstanceId()); ASSERT(_map); - GameObject* pGameObject = _map->GetGameObject(guid); - if (pGameObject) + GameObject* gameObject = _map->GetGameObject(guid); + if (gameObject) { - objectQR = sObjectMgr->GetGOQuestRelationBounds(pGameObject->GetEntry()); - objectQIR = sObjectMgr->GetGOQuestInvolvedRelationBounds(pGameObject->GetEntry()); + objectQR = sObjectMgr->GetGOQuestRelationBounds(gameObject->GetEntry()); + objectQIR = sObjectMgr->GetGOQuestInvolvedRelationBounds(gameObject->GetEntry()); } else return; @@ -14782,7 +14783,7 @@ void Player::SendPreparedQuest(uint64 guid) if (quest->IsAutoAccept() && CanAddQuest(quest, true) && CanTakeQuest(quest, true)) AddQuestAndCheckCompletion(quest, object); - if ((quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) || quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) + if (quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, CanCompleteRepeatableQuest(quest), true); else PlayerTalkClass->SendQuestGiverQuestDetails(quest, guid, true); @@ -14845,24 +14846,40 @@ bool Player::IsActiveQuest(uint32 quest_id) const Quest const* Player::GetNextQuest(uint64 guid, Quest const* quest) { QuestRelationBounds objectQR; + uint32 nextQuestID = quest->GetNextQuestInChain(); - Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, guid); - if (creature) - objectQR = sObjectMgr->GetCreatureQuestRelationBounds(creature->GetEntry()); - else + switch (GUID_HIPART(guid)) { - //we should obtain map pointer from GetMap() in 99% of cases. Special case - //only for quests which cast teleport spells on player - Map* _map = IsInWorld() ? GetMap() : sMapMgr->FindMap(GetMapId(), GetInstanceId()); - ASSERT(_map); - GameObject* pGameObject = _map->GetGameObject(guid); - if (pGameObject) - objectQR = sObjectMgr->GetGOQuestRelationBounds(pGameObject->GetEntry()); - else + case HIGHGUID_PLAYER: + ASSERT(quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)); + return sObjectMgr->GetQuestTemplate(nextQuestID); + case HIGHGUID_UNIT: + case HIGHGUID_PET: + case HIGHGUID_VEHICLE: + { + if (Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, guid)) + objectQR = sObjectMgr->GetCreatureQuestRelationBounds(creature->GetEntry()); + else + return NULL; + break; + } + case HIGHGUID_GAMEOBJECT: + { + //we should obtain map pointer from GetMap() in 99% of cases. Special case + //only for quests which cast teleport spells on player + Map* _map = IsInWorld() ? GetMap() : sMapMgr->FindMap(GetMapId(), GetInstanceId()); + ASSERT(_map); + if (GameObject* gameObject = _map->GetGameObject(guid)) + objectQR = sObjectMgr->GetGOQuestRelationBounds(gameObject->GetEntry()); + else + return NULL; + break; + } + default: return NULL; } - uint32 nextQuestID = quest->GetNextQuestInChain(); + // for unit and go state for (QuestRelations::const_iterator itr = objectQR.first; itr != objectQR.second; ++itr) { if (itr->second == nextQuestID) @@ -14912,7 +14929,7 @@ bool Player::CanAddQuest(Quest const* quest, bool msg) InventoryResult msg2 = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, srcitem, count); // player already have max number (in most case 1) source item, no additional item needed and quest can be added. - if (msg2 == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) + if (msg2 == EQUIP_ERR_ITEM_MAX_COUNT) return true; else if (msg2 != EQUIP_ERR_OK) { @@ -14935,7 +14952,7 @@ bool Player::CanCompleteQuest(uint32 quest_id) return false; // not allow re-complete quest // auto complete quest - if ((qInfo->IsAutoComplete() || qInfo->GetFlags() & QUEST_FLAGS_AUTOCOMPLETE) && CanTakeQuest(qInfo, false)) + if (qInfo->IsAutoComplete() && CanTakeQuest(qInfo, false)) return true; QuestStatusMap::iterator itr = m_QuestStatus.find(quest_id); @@ -14979,7 +14996,7 @@ bool Player::CanCompleteQuest(uint32 quest_id) if (qInfo->GetRewOrReqMoney() < 0) { - if (!HasEnoughMoney(-qInfo->GetRewOrReqMoney())) + if (!HasEnoughMoney(-int64(qInfo->GetRewOrReqMoney()))) return false; } @@ -15015,7 +15032,7 @@ bool Player::CanCompleteRepeatableQuest(Quest const* quest) bool Player::CanRewardQuest(Quest const* quest, bool msg) { // not auto complete quest and not completed quest (only cheating case, then ignore without message) - if (!quest->IsDFQuest() && !quest->IsAutoComplete() && !(quest->GetFlags() & QUEST_FLAGS_AUTOCOMPLETE) && GetQuestStatus(quest->GetQuestId()) != QUEST_STATUS_COMPLETE) + if (!quest->IsDFQuest() && !quest->IsAutoComplete() && GetQuestStatus(quest->GetQuestId()) != QUEST_STATUS_COMPLETE) return false; // daily quest can't be rewarded (25 daily quest already completed) @@ -15041,8 +15058,12 @@ bool Player::CanRewardQuest(Quest const* quest, bool msg) } } + for (uint8 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; i++) + if (quest->RequiredCurrencyId[i] && !HasCurrency(quest->RequiredCurrencyId[i], quest->RequiredCurrencyCount[i])) + return false; + // prevent receive reward with low money and GetRewOrReqMoney() < 0 - if (quest->GetRewOrReqMoney() < 0 && !HasEnoughMoney(-quest->GetRewOrReqMoney())) + if (quest->GetRewOrReqMoney() < 0 && !HasEnoughMoney(-int64(quest->GetRewOrReqMoney()))) return false; return true; @@ -15222,7 +15243,7 @@ void Player::CompleteQuest(uint32 quest_id) if (qInfo->HasFlag(QUEST_FLAGS_TRACKING)) RewardQuest(qInfo, 0, this, false); else - SendQuestComplete(quest_id); + SendQuestComplete(qInfo); } } } @@ -15251,6 +15272,10 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, if (quest->RequiredItemId[i]) DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true); + for (uint8 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i) + if (quest->RequiredCurrencyId[i]) + ModifyCurrency(quest->RequiredCurrencyId[i], -int32(quest->RequiredCurrencyCount[i])); + for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) { if (quest->RequiredSourceItemId[i]) @@ -15291,6 +15316,13 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, } } + for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) + if (quest->RewardCurrencyId[i]) + ModifyCurrency(quest->RewardCurrencyId[i], quest->RewardCurrencyCount[i]); + + if (uint32 skill = quest->GetRewardSkillId()) + UpdateSkillPro(skill, 1000, quest->GetRewardSkillPoints()); + RewardReputation(quest); uint16 log_slot = FindQuestSlot(quest_id); @@ -15300,7 +15332,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool rewarded = (m_RewardedQuests.find(quest_id) != m_RewardedQuests.end()); // Not give XP in case already completed once repeatable quest - uint32 XP = rewarded ? 0 : uint32(quest->XPValue(this)*sWorld->getRate(RATE_XP_QUEST)); + uint32 XP = rewarded ? 0 : uint32(quest->XPValue(this) * sWorld->getRate(RATE_XP_QUEST)); // handle SPELL_AURA_MOD_XP_QUEST_PCT auras Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT); @@ -15313,6 +15345,9 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, else moneyRew = int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY)); + if (Guild* guild = sGuildMgr->GetGuildById(GetGuildId())) + guild->GiveXP(uint32(quest->XPValue(this) * sWorld->getRate(RATE_XP_QUEST) * sWorld->getRate(RATE_XP_GUILD_MODIFIER)), this); + // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative if (quest->GetRewOrReqMoney()) moneyRew += quest->GetRewOrReqMoney(); @@ -15336,15 +15371,12 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, SetTitle(titleEntry); } - if (quest->GetBonusTalents()) + if (uint32 talents = quest->GetBonusTalents()) { - m_questRewardTalentCount+=quest->GetBonusTalents(); + AddQuestRewardedTalentCount(talents); InitTalentForLevel(); } - if (quest->GetRewArenaPoints()) - ModifyArenaPoints(quest->GetRewArenaPoints()); - // Send reward mail if (uint32 mail_template_id = quest->GetRewMailTemplateId()) { @@ -15924,7 +15956,7 @@ bool Player::GiveQuestSourceItem(Quest const* quest) return true; } // player already have max amount required item, just report success - else if (msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) + else if (msg == EQUIP_ERR_ITEM_MAX_COUNT) return true; else SendEquipError(msg, NULL, NULL, srcitem); @@ -16089,28 +16121,28 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) switch (questgiver->GetTypeId()) { - case TYPEID_GAMEOBJECT: - { - QuestGiverStatus questStatus = QuestGiverStatus(sScriptMgr->GetDialogStatus(this, questgiver->ToGameObject())); - if (questStatus != DIALOG_STATUS_SCRIPTED_NO_STATUS) - return questStatus; - qr = sObjectMgr->GetGOQuestRelationBounds(questgiver->GetEntry()); - qir = sObjectMgr->GetGOQuestInvolvedRelationBounds(questgiver->GetEntry()); - break; - } - case TYPEID_UNIT: - { - QuestGiverStatus questStatus = QuestGiverStatus(sScriptMgr->GetDialogStatus(this, questgiver->ToCreature())); - if (questStatus != DIALOG_STATUS_SCRIPTED_NO_STATUS) - return questStatus; - qr = sObjectMgr->GetCreatureQuestRelationBounds(questgiver->GetEntry()); - qir = sObjectMgr->GetCreatureQuestInvolvedRelationBounds(questgiver->GetEntry()); - break; - } - default: - // it's impossible, but check - TC_LOG_ERROR("entities.player.quest", "GetQuestDialogStatus called for unexpected type %u", questgiver->GetTypeId()); - return DIALOG_STATUS_NONE; + case TYPEID_GAMEOBJECT: + { + QuestGiverStatus questStatus = QuestGiverStatus(sScriptMgr->GetDialogStatus(this, questgiver->ToGameObject())); + if (questStatus != DIALOG_STATUS_SCRIPTED_NO_STATUS) + return questStatus; + qr = sObjectMgr->GetGOQuestRelationBounds(questgiver->GetEntry()); + qir = sObjectMgr->GetGOQuestInvolvedRelationBounds(questgiver->GetEntry()); + break; + } + case TYPEID_UNIT: + { + QuestGiverStatus questStatus = QuestGiverStatus(sScriptMgr->GetDialogStatus(this, questgiver->ToCreature())); + if (questStatus != DIALOG_STATUS_SCRIPTED_NO_STATUS) + return questStatus; + qr = sObjectMgr->GetCreatureQuestRelationBounds(questgiver->GetEntry()); + qir = sObjectMgr->GetCreatureQuestInvolvedRelationBounds(questgiver->GetEntry()); + break; + } + default: + // it's impossible, but check + TC_LOG_ERROR("entities.player.quest", "GetQuestDialogStatus called for unexpected type %u", questgiver->GetTypeId()); + return DIALOG_STATUS_NONE; } QuestGiverStatus result = DIALOG_STATUS_NONE; @@ -16357,6 +16389,9 @@ void Player::ItemAddedQuestCheck(uint32 entry, uint32 count) { q_status.ItemCount[j] = std::min<uint16>(q_status.ItemCount[j] + count, reqitemcount); m_QuestStatusSave[questid] = true; + + //SendQuestUpdateAddItem(qInfo, j, additemcount); + // FIXME: verify if there's any packet sent updating item } if (CanCompleteQuest(questid)) CompleteQuest(questid); @@ -16435,7 +16470,7 @@ void Player::KilledMonsterCredit(uint32 entry, uint64 guid /*= 0*/) } StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_CREATURE, real_entry); // MUST BE CALLED FIRST - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, real_entry, addkillcount, killed); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, real_entry, addkillcount, 0, killed); for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) { @@ -16779,39 +16814,50 @@ bool Player::HasQuestForItem(uint32 itemid) const return false; } -void Player::SendQuestComplete(uint32 quest_id) +void Player::SendQuestComplete(Quest const* quest) { - if (quest_id) + if (quest) { WorldPacket data(SMSG_QUESTUPDATE_COMPLETE, 4); - data << uint32(quest_id); + data << uint32(quest->GetQuestId()); GetSession()->SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTUPDATE_COMPLETE quest = %u", quest_id); + TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTUPDATE_COMPLETE quest = %u", quest->GetQuestId()); } } void Player::SendQuestReward(Quest const* quest, uint32 XP) { - uint32 questid = quest->GetQuestId(); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid); - sGameEventMgr->HandleQuestComplete(questid); - WorldPacket data(SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4)); - data << uint32(questid); + uint32 questId = quest->GetQuestId(); + TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questId); + sGameEventMgr->HandleQuestComplete(questId); + + uint32 xp; + uint32 moneyReward; if (getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { - data << uint32(XP); - data << uint32(quest->GetRewOrReqMoney()); + xp = XP; + moneyReward = quest->GetRewOrReqMoney(); } - else + else // At max level, increase gold reward { - data << uint32(0); - data << uint32(quest->GetRewOrReqMoney() + int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY))); + xp = 0; + moneyReward = uint32(quest->GetRewOrReqMoney() + int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY))); } - data << uint32(10 * quest->CalculateHonorGain(GetQuestLevel(quest))); - data << uint32(quest->GetBonusTalents()); // bonus talents - data << uint32(quest->GetRewArenaPoints()); + WorldPacket data(SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4)); + + data << uint32(quest->GetBonusTalents()); // bonus talents (not verified for 4.x) + data << uint32(quest->GetRewardSkillPoints()); // 4.x bonus skill points + data << uint32(moneyReward); + data << uint32(xp); + data << uint32(questId); + data << uint32(quest->GetRewardSkillId()); // 4.x bonus skill id + + data.WriteBit(0); // FIXME: unknown bits, common values sent + data.WriteBit(1); + data.FlushBits(); + GetSession()->SendPacket(&data); } @@ -16879,15 +16925,6 @@ void Player::SendPushToPartyResponse(Player* player, uint8 msg) } } -void Player::SendQuestUpdateAddItem(Quest const* /*quest*/, uint32 /*item_idx*/, uint16 /*count*/) -{ - WorldPacket data(SMSG_QUESTUPDATE_ADD_ITEM, 0); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTUPDATE_ADD_ITEM"); - //data << quest->RequiredItemId[item_idx]; - //data << count; - GetSession()->SendPacket(&data); -} - void Player::SendQuestUpdateAddCreatureOrGo(Quest const* quest, uint64 guid, uint32 creatureOrGO_idx, uint16 old_count, uint16 add_count) { ASSERT(old_count + add_count < 65536 && "mob/GO count store in 16 bits 2^16 = 65536 (0..65536)"); @@ -17128,12 +17165,14 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) //QueryResult* result = CharacterDatabase.PQuery("SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " // 12 13 14 15 16 17 18 19 20 21 22 23 24 //"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " - // 25 26 27 28 29 30 31 32 33 34 35 36 37 38 - //"resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, " - // 39 40 41 42 43 44 45 46 47 48 49 - //"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, " - // 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 - //"health, power1, power2, power3, power4, power5, power6, power7, instance_id, speccount, activespec, exploredZones, equipmentCache, ammoId, knownTitles, actionBars, grantableLevels FROM characters WHERE guid = '%u'", guid); + // 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 + //"resettalents_time, talentTree, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, " + // 40 41 42 43 44 45 + //"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, " + // 46 47 48 49 50 51 52 53 54 55 56 + //"health, power1, power2, power3, power4, power5, instance_id, speccount, activespec, exploredZones, equipmentCache, " + // 57 58 59 + //"knownTitles, actionBars, grantableLevels FROM characters WHERE guid = '%u'", guid); PreparedQueryResult result = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM); if (!result) { @@ -17205,8 +17244,8 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8()); SetUInt32Value(PLAYER_XP, fields[7].GetUInt32()); - _LoadIntoDataField(fields[61].GetCString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE); - _LoadIntoDataField(fields[64].GetCString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE*2); + _LoadIntoDataField(fields[55].GetCString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE); + _LoadIntoDataField(fields[57].GetCString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE*2); SetObjectScale(1.0f); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); @@ -17214,7 +17253,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) // load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria) m_achievementMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS)); - uint32 money = fields[8].GetUInt32(); + uint64 money = fields[8].GetUInt64(); if (money > MAX_MONEY_AMOUNT) money = MAX_MONEY_AMOUNT; SetMoney(money); @@ -17222,16 +17261,12 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) SetUInt32Value(PLAYER_BYTES, fields[9].GetUInt32()); SetUInt32Value(PLAYER_BYTES_2, fields[10].GetUInt32()); SetByteValue(PLAYER_BYTES_3, 0, fields[5].GetUInt8()); - SetByteValue(PLAYER_BYTES_3, 1, fields[49].GetUInt8()); + SetByteValue(PLAYER_BYTES_3, 1, fields[45].GetUInt8()); SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32()); - SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[48].GetUInt32()); - - SetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES, fields[47].GetUInt64()); - - SetUInt32Value(PLAYER_AMMO_ID, fields[63].GetUInt32()); + SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[44].GetUInt32()); // set which actionbars the client has active - DO NOT REMOVE EVER AGAIN (can be changed though, if it does change fieldwise) - SetByteValue(PLAYER_FIELD_BYTES, 2, fields[65].GetUInt8()); + SetByteValue(PLAYER_FIELD_BYTES, 2, fields[58].GetUInt8()); InitDisplayIds(); @@ -17259,21 +17294,23 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) InitPrimaryProfessions(); // to max set before any spell loaded // init saved position, and fix it later if problematic - uint32 transLowGUID = fields[30].GetUInt32(); + uint32 transLowGUID = uint32(fields[31].GetUInt32()); + Relocate(fields[12].GetFloat(), fields[13].GetFloat(), fields[14].GetFloat(), fields[16].GetFloat()); + uint32 mapId = fields[15].GetUInt16(); - uint32 instanceId = fields[58].GetUInt32(); + uint32 instanceId = fields[52].GetUInt32(); - uint32 dungeonDiff = fields[38].GetUInt8() & 0x0F; + uint32 dungeonDiff = fields[39].GetUInt8() & 0x0F; if (dungeonDiff >= MAX_DUNGEON_DIFFICULTY) dungeonDiff = DUNGEON_DIFFICULTY_NORMAL; - uint32 raidDiff = (fields[38].GetUInt8() >> 4) & 0x0F; + uint32 raidDiff = (fields[39].GetUInt8() >> 4) & 0x0F; if (raidDiff >= MAX_RAID_DIFFICULTY) raidDiff = RAID_DIFFICULTY_10MAN_NORMAL; SetDungeonDifficulty(Difficulty(dungeonDiff)); // may be changed in _LoadGroup SetRaidDifficulty(Difficulty(raidDiff)); // may be changed in _LoadGroup - std::string taxi_nodes = fields[37].GetString(); + std::string taxi_nodes = fields[38].GetString(); #define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); } @@ -17281,8 +17318,6 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) _LoadArenaTeamInfo(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO)); - SetArenaPoints(fields[39].GetUInt32()); - // check arena teams integrity for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot) { @@ -17299,12 +17334,10 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) SetArenaTeamInfoField(arena_slot, ArenaTeamInfoType(j), 0); } - SetHonorPoints(fields[40].GetUInt32()); - SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, fields[41].GetUInt32()); - SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, fields[42].GetUInt32()); - SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, fields[43].GetUInt32()); - SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[44].GetUInt16()); - SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[45].GetUInt16()); + _LoadCurrency(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CURRENCY)); + SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, fields[40].GetUInt32()); + SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[41].GetUInt16()); + SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[42].GetUInt16()); _LoadBoundInstances(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES)); _LoadInstanceTimeRestrictions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES)); @@ -17375,7 +17408,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) if (transport) { - float x = fields[26].GetFloat(), y = fields[27].GetFloat(), z = fields[28].GetFloat(), o = fields[29].GetFloat(); + float x = fields[27].GetFloat(), y = fields[28].GetFloat(), z = fields[29].GetFloat(), o = fields[30].GetFloat(); m_movementInfo.transport.pos.Relocate(x, y, z, o); transport->CalculatePassengerPosition(x, y, z, &o); @@ -17402,7 +17435,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) } else { - TC_LOG_ERROR("entities.player", "Player (guidlow %u) have problems with transport guid (%u). Teleport to bind location.", + TC_LOG_ERROR("entities.player", "Player (guidlow %d) have problems with transport guid (%u). Teleport to bind location.", guid, transLowGUID); RelocateToHomebind(); @@ -17476,7 +17509,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) // NOW player must have valid map // load the player's map here if it's not already loaded Map* map = sMapMgr->CreateMap(mapId, this); - AreaTrigger const* areaTrigger = NULL; + AreaTriggerStruct const* areaTrigger = NULL; bool check = false; if (!map) @@ -17555,21 +17588,21 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) m_Played_time[PLAYED_TIME_TOTAL]= fields[19].GetUInt32(); m_Played_time[PLAYED_TIME_LEVEL]= fields[20].GetUInt32(); - m_resetTalentsCost = fields[24].GetUInt32(); - m_resetTalentsTime = time_t(fields[25].GetUInt32()); + SetTalentResetCost(fields[24].GetUInt32()); + SetTalentResetTime(time_t(fields[25].GetUInt32())); m_taxi.LoadTaxiMask(fields[17].GetString()); // must be before InitTaxiNodesForLevel - uint32 extraflags = fields[31].GetUInt16(); + uint32 extraflags = fields[32].GetUInt16(); - m_stableSlots = fields[32].GetUInt8(); + m_stableSlots = fields[33].GetUInt8(); if (m_stableSlots > MAX_PET_STABLES) { TC_LOG_ERROR("entities.player", "Player can have not more %u stable slots, but have in DB %u", MAX_PET_STABLES, uint32(m_stableSlots)); m_stableSlots = MAX_PET_STABLES; } - m_atLoginFlags = fields[33].GetUInt16(); + m_atLoginFlags = fields[34].GetUInt16(); if (HasAtLoginFlag(AT_LOGIN_RENAME)) { @@ -17582,7 +17615,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) m_lastHonorUpdateTime = logoutTime; UpdateHonorFields(); - m_deathExpireTime = time_t(fields[36].GetUInt32()); + m_deathExpireTime = time_t(fields[37].GetUInt32()); if (m_deathExpireTime > now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP) m_deathExpireTime = now + MAX_DEATH_COUNT * DEATH_EXPIRE_STEP - 1; @@ -17643,14 +17676,26 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) //mails are loaded only when needed ;-) - when player in game click on mailbox. //_LoadMail(); - m_specsCount = fields[59].GetUInt8(); - m_activeSpec = fields[60].GetUInt8(); + SetSpecsCount(fields[53].GetUInt8()); + SetActiveSpec(fields[54].GetUInt8()); // sanity check - if (m_specsCount > MAX_TALENT_SPECS || m_activeSpec > MAX_TALENT_SPEC || m_specsCount < MIN_TALENT_SPECS) + if (GetSpecsCount() > MAX_TALENT_SPECS || GetActiveSpec() > MAX_TALENT_SPEC || GetSpecsCount() < MIN_TALENT_SPECS) { - m_activeSpec = 0; - TC_LOG_ERROR("entities.player", "Player %s(GUID: %u) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUIDLow(), m_specsCount, m_activeSpec); + SetActiveSpec(0); + TC_LOG_ERROR("entities.player", "Player %s(GUID: %u) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUIDLow(), GetSpecsCount(), GetActiveSpec()); + } + + // Only load selected specializations, learning mastery spells requires this + Tokenizer talentTrees(fields[26].GetString(), ' ', MAX_TALENT_SPECS); + for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + { + if (i >= talentTrees.size()) + break; + + uint32 talentTree = atol(talentTrees[i]); + if (sTalentTabStore.LookupEntry(talentTree)) + SetPrimaryTalentTree(i, talentTree); } _LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS)); @@ -17682,6 +17727,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), time_diff); + if (IsVoidStorageUnlocked()) + _LoadVoidStorage(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE)); + // update items with duration and realtime UpdateItemDuration(time_diff, true); @@ -17694,7 +17742,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) // check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES // note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded - uint32 curTitle = fields[46].GetUInt32(); + uint32 curTitle = fields[43].GetUInt32(); if (curTitle && !HasTitle(curTitle)) curTitle = 0; @@ -17717,12 +17765,35 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) UpdateAllStats(); // restore remembered power/health values (but not more max values) - uint32 savedHealth = fields[50].GetUInt32(); + uint32 savedHealth = fields[46].GetUInt32(); SetHealth(savedHealth > GetMaxHealth() ? GetMaxHealth() : savedHealth); - for (uint8 i = 0; i < MAX_POWERS; ++i) + uint32 loadedPowers = 0; + for (uint32 i = 0; i < MAX_POWERS; ++i) { - uint32 savedPower = fields[51+i].GetUInt32(); - SetPower(Powers(i), savedPower > GetMaxPower(Powers(i)) ? GetMaxPower(Powers(i)) : savedPower); + if (GetPowerIndex(i) != MAX_POWERS) + { + uint32 savedPower = fields[47+loadedPowers].GetUInt32(); + uint32 maxPower = GetUInt32Value(UNIT_FIELD_MAXPOWER1 + loadedPowers); + SetPower(Powers(i), (savedPower > maxPower) ? maxPower : savedPower); + if (++loadedPowers >= MAX_POWERS_PER_CLASS) + break; + } + } + + for (; loadedPowers < MAX_POWERS_PER_CLASS; ++loadedPowers) + SetUInt32Value(UNIT_FIELD_POWER1 + loadedPowers, 0); + + SetPower(POWER_ECLIPSE, 0); + + // Verify loaded talent specializations + for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + { + if (i >= talentTrees.size()) + break; + + uint32 talentTree = atol(talentTrees[i]); + if (talentTree != 0 && !sTalentTabStore.LookupEntry(talentTree) && i == GetActiveSpec()) + SetAtLoginFlag(AT_LOGIN_RESET_TALENTS); // invalid tree, reset talents } TC_LOG_DEBUG("entities.player.loading", "The value of player %s after load item and aura is: ", m_name.c_str()); @@ -17777,7 +17848,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) } // RaF stuff. - m_grantableLevels = fields[66].GetUInt8(); + m_grantableLevels = fields[59].GetUInt8(); if (GetSession()->IsARecruiter() || (GetSession()->GetRecruiterId() != 0)) SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_REFER_A_FRIEND); @@ -17786,13 +17857,50 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) _LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES)); - m_achievementMgr->CheckAllAchievementCriteria(); + m_achievementMgr->CheckAllAchievementCriteria(this); _LoadEquipmentSets(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS)); + _LoadCUFProfiles(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES)); + return true; } +void Player::_LoadCUFProfiles(PreparedQueryResult result) +{ + if (!result) + return; + + do + { + // SELECT id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, unk146, unk147, unk148, unk150, unk152, unk154 FROM character_cuf_profiles WHERE guid = ? + Field* fields = result->Fetch(); + + uint8 id = fields[0].GetUInt8(); + std::string name = fields[1].GetString(); + uint16 frameHeight = fields[2].GetUInt16(); + uint16 frameWidth = fields[3].GetUInt16(); + uint8 sortBy = fields[4].GetUInt8(); + uint8 healthText = fields[5].GetUInt8(); + uint32 boolOptions = fields[6].GetUInt32(); + uint8 unk146 = fields[7].GetUInt8(); + uint8 unk147 = fields[8].GetUInt8(); + uint8 unk148 = fields[9].GetUInt8(); + uint16 unk150 = fields[10].GetUInt16(); + uint16 unk152 = fields[11].GetUInt16(); + uint16 unk154 = fields[12].GetUInt16(); + + if (id > MAX_CUF_PROFILES) + { + TC_LOG_ERROR("entities.player", "Player::_LoadCUFProfiles - Player (GUID: %u, name: %s) has an CUF profile with invalid id (id: %u), max is %i.", GetGUIDLow(), GetName().c_str(), id, MAX_CUF_PROFILES); + continue; + } + + _CUFProfiles[id] = new CUFProfile(name, frameHeight, frameWidth, sortBy, healthText, boolOptions, unk146, unk147, unk148, unk150, unk152, unk154); + } + while (result->NextRow()); +} + bool Player::isAllowedToLoot(const Creature* creature) { if (!creature->isDead() || !creature->IsDamageEnoughForLootingAndReward()) @@ -17949,7 +18057,7 @@ void Player::_LoadGlyphAuras() { for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) { - if (uint32 glyph = GetGlyph(i)) + if (uint32 glyph = GetGlyph(GetActiveSpec(), i)) { if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph)) { @@ -18073,7 +18181,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) { std::map<uint32, Item*>::iterator itr = invalidBagMap.find(bagGuid); if (std::find(problematicItems.begin(), problematicItems.end(), itr->second) != problematicItems.end()) - err = EQUIP_ERR_INT_BAG_ERROR; + err = EQUIP_ERR_INTERNAL_BAG_ERROR; } else { @@ -18120,6 +18228,53 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) _ApplyAllItemMods(); } +void Player::_LoadVoidStorage(PreparedQueryResult result) +{ + if (!result) + return; + + do + { + // SELECT itemid, itemEntry, slot, creatorGuid FROM character_void_storage WHERE playerGuid = ? + Field* fields = result->Fetch(); + + uint64 itemId = fields[0].GetUInt64(); + uint32 itemEntry = fields[1].GetUInt32(); + uint8 slot = fields[2].GetUInt8(); + uint32 creatorGuid = fields[3].GetUInt32(); + uint32 randomProperty = fields[4].GetUInt32(); + uint32 suffixFactor = fields[5].GetUInt32(); + + if (!itemId) + { + TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage - Player (GUID: %u, name: %s) has an item with an invalid id (item id: " UI64FMTD ", entry: %u).", GetGUIDLow(), GetName().c_str(), itemId, itemEntry); + continue; + } + + if (!sObjectMgr->GetItemTemplate(itemEntry)) + { + TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage - Player (GUID: %u, name: %s) has an item with an invalid entry (item id: " UI64FMTD ", entry: %u).", GetGUIDLow(), GetName().c_str(), itemId, itemEntry); + continue; + } + + if (slot >= VOID_STORAGE_MAX_SLOT) + { + TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage - Player (GUID: %u, name: %s) has an item with an invalid slot (item id: " UI64FMTD ", entry: %u, slot: %u).", GetGUIDLow(), GetName().c_str(), itemId, itemEntry, slot); + continue; + } + + std::string name; + if (creatorGuid && !sObjectMgr->GetPlayerNameByGUID(creatorGuid, name)) + { + TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage - Player (GUID: %u, name: %s) has an item with an invalid creator guid, set to 0 (item id: " UI64FMTD ", entry: %u, creatorGuid: %u).", GetGUIDLow(), GetName().c_str(), itemId, itemEntry, creatorGuid); + creatorGuid = 0; + } + + _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, randomProperty, suffixFactor); + } + while (result->NextRow()); +} + Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields) { Item* item = NULL; @@ -18341,8 +18496,8 @@ void Player::_LoadMail() bool has_items = fields[6].GetBool(); m->expire_time = time_t(fields[7].GetUInt32()); m->deliver_time = time_t(fields[8].GetUInt32()); - m->money = fields[9].GetUInt32(); - m->COD = fields[10].GetUInt32(); + m->money = fields[9].GetUInt64(); + m->COD = fields[10].GetUInt64(); m->checked = fields[11].GetUInt8(); m->stationery = fields[12].GetUInt8(); m->mailTemplateId = fields[13].GetInt16(); @@ -18492,8 +18647,8 @@ void Player::_LoadQuestStatusRewarded(PreparedQueryResult result) SetTitle(titleEntry); } - if (quest->GetBonusTalents()) - m_questRewardTalentCount += quest->GetBonusTalents(); + if (uint32 talents = quest->GetBonusTalents()) + AddQuestRewardedTalentCount(talents); } m_RewardedQuests.insert(quest_id); @@ -18688,7 +18843,7 @@ void Player::_LoadBoundInstances(PreparedQueryResult result) bool deleteInstance = false; MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); - std::string mapname = mapEntry ? mapEntry->name[sWorld->GetDefaultDbcLocale()] : "Unknown"; + std::string mapname = mapEntry ? mapEntry->name : "Unknown"; if (!mapEntry || !mapEntry->IsDungeon()) { @@ -18882,16 +19037,25 @@ void Player::SendRaidInfo() if (itr->second.perm) { InstanceSave* save = itr->second.save; + bool isHeroic = save->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC || save->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC; + uint32 completedEncounters = 0; + if (Map* map = sMapMgr->FindMap(save->GetMapId(), save->GetInstanceId())) + if (InstanceScript* instanceScript = ((InstanceMap*)map)->GetInstanceScript()) + completedEncounters = instanceScript->GetCompletedEncounterMask(); + data << uint32(save->GetMapId()); // map id data << uint32(save->GetDifficulty()); // difficulty + data << uint32(isHeroic); // heroic data << uint64(save->GetInstanceId()); // instance id data << uint8(1); // expired = 0 data << uint8(0); // extended = 1 data << uint32(save->GetResetTime() - now); // reset time + data << uint32(completedEncounters); // completed encounters mask ++counter; } } } + data.put<uint32>(p_counter, counter); GetSession()->SendPacket(&data); } @@ -18916,8 +19080,8 @@ void Player::SendSavedInstances() } } - //Send opcode 811. true or false means, whether you have current raid/heroic instances - data.Initialize(SMSG_UPDATE_INSTANCE_OWNERSHIP); + //Send opcode SMSG_UPDATE_INSTANCE_OWNERSHIP. true or false means, whether you have current raid/heroic instances + data.Initialize(SMSG_UPDATE_INSTANCE_OWNERSHIP, 4); data << uint32(hasBeenSaved); GetSession()->SendPacket(&data); @@ -18930,7 +19094,7 @@ void Player::SendSavedInstances() { if (itr->second.perm) { - data.Initialize(SMSG_UPDATE_LAST_INSTANCE); + data.Initialize(SMSG_UPDATE_LAST_INSTANCE, 4); data << uint32(itr->second.save->GetMapId()); GetSession()->SendPacket(&data); } @@ -19078,7 +19242,8 @@ bool Player::_LoadHomeBind(PreparedQueryResult result) PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); if (!info) { - TC_LOG_ERROR("entities.player", "Player (Name %s) has incorrect race/class pair. Can't be loaded.", GetName().c_str()); + TC_LOG_ERROR("entities.player", "Player (Name %s) has incorrect race/class (%u/%u) pair. Can't be loaded.", + GetName().c_str(), uint32(getRace()), uint32(getClass())); return false; } @@ -19173,7 +19338,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt8(index++, getGender()); stmt->setUInt8(index++, getLevel()); stmt->setUInt32(index++, GetUInt32Value(PLAYER_XP)); - stmt->setUInt32(index++, GetMoney()); + stmt->setUInt64(index++, GetMoney()); stmt->setUInt32(index++, GetUInt32Value(PLAYER_BYTES)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_BYTES_2)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_FLAGS)); @@ -19204,8 +19369,13 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt8(index++, (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0)); //save, far from tavern/city //save, but in tavern/city - stmt->setUInt32(index++, m_resetTalentsCost); - stmt->setUInt32(index++, uint32(m_resetTalentsTime)); + stmt->setUInt32(index++, GetTalentResetCost()); + stmt->setUInt32(index++, GetTalentResetTime()); + + ss.str(""); + for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + ss << GetPrimaryTalentTree(i) << " "; + stmt->setString(index++, ss.str()); stmt->setUInt16(index++, (uint16)m_ExtraFlags); stmt->setUInt8(index++, m_stableSlots); stmt->setUInt16(index++, (uint16)m_atLoginFlags); @@ -19216,26 +19386,32 @@ void Player::SaveToDB(bool create /*=false*/) ss << m_taxi.SaveTaxiDestinationsToString(); stmt->setString(index++, ss.str()); - stmt->setUInt32(index++, GetArenaPoints()); - stmt->setUInt32(index++, GetHonorPoints()); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); stmt->setUInt16(index++, GetUInt16Value(PLAYER_FIELD_KILLS, 0)); stmt->setUInt16(index++, GetUInt16Value(PLAYER_FIELD_KILLS, 1)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_CHOSEN_TITLE)); - stmt->setUInt64(index++, GetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX)); stmt->setUInt8(index++, GetDrunkValue()); stmt->setUInt32(index++, GetHealth()); + uint32 storedPowers = 0; for (uint32 i = 0; i < MAX_POWERS; ++i) - stmt->setUInt32(index++, GetPower(Powers(i))); + { + if (GetPowerIndex(i) != MAX_POWERS) + { + stmt->setUInt32(index++, GetUInt32Value(UNIT_FIELD_POWER1 + storedPowers)); + if (++storedPowers >= MAX_POWERS_PER_CLASS) + break; + } + } + + for (; storedPowers < MAX_POWERS_PER_CLASS; ++storedPowers) + stmt->setUInt32(index++, 0); stmt->setUInt32(index++, GetSession()->GetLatency()); - stmt->setUInt8(index++, m_specsCount); - stmt->setUInt8(index++, m_activeSpec); + stmt->setUInt8(index++, GetSpecsCount()); + stmt->setUInt8(index++, GetActiveSpec()); ss.str(""); for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i) @@ -19256,15 +19432,13 @@ void Player::SaveToDB(bool create /*=false*/) ss << '0'; ss << " 0 "; } - stmt->setString(index++, ss.str()); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_AMMO_ID)); ss.str(""); for (uint32 i = 0; i < KNOWN_TITLES_SIZE*2; ++i) ss << GetUInt32Value(PLAYER__FIELD_KNOWN_TITLES + i) << ' '; - stmt->setString(index++, ss.str()); + stmt->setUInt8(index++, GetByteValue(PLAYER_FIELD_BYTES, 2)); stmt->setUInt32(index++, m_grantableLevels); } @@ -19278,7 +19452,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt8(index++, getGender()); stmt->setUInt8(index++, getLevel()); stmt->setUInt32(index++, GetUInt32Value(PLAYER_XP)); - stmt->setUInt32(index++, GetMoney()); + stmt->setUInt64(index++, GetMoney()); stmt->setUInt32(index++, GetUInt32Value(PLAYER_BYTES)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_BYTES_2)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_FLAGS)); @@ -19324,8 +19498,13 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt8(index++, (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0)); //save, far from tavern/city //save, but in tavern/city - stmt->setUInt32(index++, m_resetTalentsCost); - stmt->setUInt32(index++, uint32(m_resetTalentsTime)); + stmt->setUInt32(index++, GetTalentResetCost()); + stmt->setUInt32(index++, GetTalentResetTime()); + + ss.str(""); + for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + ss << GetPrimaryTalentTree(i) << " "; + stmt->setString(index++, ss.str()); stmt->setUInt16(index++, (uint16)m_ExtraFlags); stmt->setUInt8(index++, m_stableSlots); stmt->setUInt16(index++, (uint16)m_atLoginFlags); @@ -19336,26 +19515,32 @@ void Player::SaveToDB(bool create /*=false*/) ss << m_taxi.SaveTaxiDestinationsToString(); stmt->setString(index++, ss.str()); - stmt->setUInt32(index++, GetArenaPoints()); - stmt->setUInt32(index++, GetHonorPoints()); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); stmt->setUInt16(index++, GetUInt16Value(PLAYER_FIELD_KILLS, 0)); stmt->setUInt16(index++, GetUInt16Value(PLAYER_FIELD_KILLS, 1)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_CHOSEN_TITLE)); - stmt->setUInt64(index++, GetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES)); stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX)); stmt->setUInt8(index++, GetDrunkValue()); stmt->setUInt32(index++, GetHealth()); + uint32 storedPowers = 0; for (uint32 i = 0; i < MAX_POWERS; ++i) - stmt->setUInt32(index++, GetPower(Powers(i))); + { + if (GetPowerIndex(i) != MAX_POWERS) + { + stmt->setUInt32(index++, GetUInt32Value(UNIT_FIELD_POWER1 + storedPowers)); + if (++storedPowers >= MAX_POWERS_PER_CLASS) + break; + } + } + + for (; storedPowers < MAX_POWERS_PER_CLASS; ++storedPowers) + stmt->setUInt32(index++, 0); stmt->setUInt32(index++, GetSession()->GetLatency()); - stmt->setUInt8(index++, m_specsCount); - stmt->setUInt8(index++, m_activeSpec); + stmt->setUInt8(index++, GetSpecsCount()); + stmt->setUInt8(index++, GetActiveSpec()); ss.str(""); for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i) @@ -19378,7 +19563,6 @@ void Player::SaveToDB(bool create /*=false*/) } stmt->setString(index++, ss.str()); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_AMMO_ID)); ss.str(""); for (uint32 i = 0; i < KNOWN_TITLES_SIZE*2; ++i) @@ -19402,6 +19586,7 @@ void Player::SaveToDB(bool create /*=false*/) _SaveBGData(trans); _SaveInventory(trans); + _SaveVoidStorage(trans); _SaveQuestStatus(trans); _SaveDailyQuestStatus(trans); _SaveWeeklyQuestStatus(trans); @@ -19419,6 +19604,8 @@ void Player::SaveToDB(bool create /*=false*/) GetSession()->SaveTutorialsData(trans); // changed only while character in game _SaveGlyphs(trans); _SaveInstanceTimeRestrictions(trans); + _SaveCurrency(trans); + _SaveCUFProfiles(trans); // check if stats should only be saved on logout // save stats can be out of transaction @@ -19436,13 +19623,14 @@ void Player::SaveToDB(bool create /*=false*/) void Player::SaveInventoryAndGoldToDB(SQLTransaction& trans) { _SaveInventory(trans); + _SaveCurrency(trans); SaveGoldToDB(trans); } void Player::SaveGoldToDB(SQLTransaction& trans) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_MONEY); - stmt->setUInt32(0, GetMoney()); + stmt->setUInt64(0, GetMoney()); stmt->setUInt32(1, GetGUIDLow()); trans->Append(stmt); } @@ -19458,7 +19646,7 @@ void Player::_SaveActions(SQLTransaction& trans) case ACTIONBUTTON_NEW: stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACTION); stmt->setUInt32(0, GetGUIDLow()); - stmt->setUInt8(1, m_activeSpec); + stmt->setUInt8(1, GetActiveSpec()); stmt->setUInt8(2, itr->first); stmt->setUInt32(3, itr->second.GetAction()); stmt->setUInt8(4, uint8(itr->second.GetType())); @@ -19473,7 +19661,7 @@ void Player::_SaveActions(SQLTransaction& trans) stmt->setUInt8(1, uint8(itr->second.GetType())); stmt->setUInt32(2, GetGUIDLow()); stmt->setUInt8(3, itr->first); - stmt->setUInt8(4, m_activeSpec); + stmt->setUInt8(4, GetActiveSpec()); trans->Append(stmt); itr->second.uState = ACTIONBUTTON_UNCHANGED; @@ -19483,7 +19671,7 @@ void Player::_SaveActions(SQLTransaction& trans) stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC); stmt->setUInt32(0, GetGUIDLow()); stmt->setUInt8(1, itr->first); - stmt->setUInt8(2, m_activeSpec); + stmt->setUInt8(2, GetActiveSpec()); trans->Append(stmt); m_actionButtons.erase(itr++); @@ -19642,7 +19830,7 @@ void Player::_SaveInventory(SQLTransaction& trans) // save all changes to the item... if (item->GetState() != ITEM_NEW) // only for existing items, no dupes item->SaveToDB(trans); - // ...but do not save position in invntory + // ...but do not save position in inventory continue; } } @@ -19671,6 +19859,76 @@ void Player::_SaveInventory(SQLTransaction& trans) m_itemUpdateQueue.clear(); } +void Player::_SaveVoidStorage(SQLTransaction& trans) +{ + PreparedStatement* stmt = NULL; + uint32 lowGuid = GetGUIDLow(); + + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + { + if (!_voidStorageItems[i]) // unused item + { + // DELETE FROM void_storage WHERE slot = ? AND playerGuid = ? + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_SLOT); + stmt->setUInt8(0, i); + stmt->setUInt32(1, lowGuid); + } + else + { + // REPLACE INTO character_inventory (itemId, playerGuid, itemEntry, slot, creatorGuid) VALUES (?, ?, ?, ?, ?) + stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM); + stmt->setUInt64(0, _voidStorageItems[i]->ItemId); + stmt->setUInt32(1, lowGuid); + stmt->setUInt32(2, _voidStorageItems[i]->ItemEntry); + stmt->setUInt8(3, i); + stmt->setUInt32(4, _voidStorageItems[i]->CreatorGuid); + stmt->setUInt32(5, _voidStorageItems[i]->ItemRandomPropertyId); + stmt->setUInt32(6, _voidStorageItems[i]->ItemSuffixFactor); + } + + trans->Append(stmt); + } +} + + +void Player::_SaveCUFProfiles(SQLTransaction& trans) +{ + PreparedStatement* stmt = NULL; + uint32 lowGuid = GetGUIDLow(); + + for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) + { + if (!_CUFProfiles[i]) // unused profile + { + // DELETE FROM character_cuf_profiles WHERE guid = ? and id = ? + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_CUF_PROFILES); + stmt->setUInt32(0, lowGuid); + stmt->setUInt8(1, i); + } + else + { + // REPLACE INTO character_cuf_profiles (guid, id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, unk146, unk147, unk148, unk150, unk152, unk154) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_CUF_PROFILES); + stmt->setUInt32(0, lowGuid); + stmt->setUInt8(1, i); + stmt->setString(2, _CUFProfiles[i]->ProfileName); + stmt->setUInt16(3, _CUFProfiles[i]->FrameHeight); + stmt->setUInt16(4, _CUFProfiles[i]->FrameWidth); + stmt->setUInt8(5, _CUFProfiles[i]->SortBy); + stmt->setUInt8(6, _CUFProfiles[i]->HealthText); + stmt->setUInt32(7, _CUFProfiles[i]->BoolOptions.to_ulong()); // 27 of 32 fields used, fits in an int + stmt->setUInt8(8, _CUFProfiles[i]->Unk146); + stmt->setUInt8(9, _CUFProfiles[i]->Unk147); + stmt->setUInt8(10, _CUFProfiles[i]->Unk148); + stmt->setUInt16(11, _CUFProfiles[i]->Unk150); + stmt->setUInt16(12, _CUFProfiles[i]->Unk152); + stmt->setUInt16(13, _CUFProfiles[i]->Unk154); + } + + trans->Append(stmt); + } +} + void Player::_SaveMail(SQLTransaction& trans) { if (!m_mailsLoaded) @@ -19955,9 +20213,11 @@ void Player::_SaveSkills(SQLTransaction& trans) continue; } - uint32 valueData = GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)); - uint16 value = SKILL_VALUE(valueData); - uint16 max = SKILL_MAX(valueData); + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; + + uint16 value = GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset); + uint16 max = GetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset); switch (itr->second.uState) { @@ -19968,7 +20228,6 @@ void Player::_SaveSkills(SQLTransaction& trans) stmt->setUInt16(2, value); stmt->setUInt16(3, max); trans->Append(stmt); - break; case SKILL_CHANGED: stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_SKILLS); @@ -19977,13 +20236,12 @@ void Player::_SaveSkills(SQLTransaction& trans) stmt->setUInt32(2, GetGUIDLow()); stmt->setUInt16(3, uint16(itr->first)); trans->Append(stmt); - break; default: break; } - itr->second.uState = SKILL_UNCHANGED; + itr->second.uState = SKILL_UNCHANGED; ++itr; } } @@ -20046,7 +20304,7 @@ void Player::_SaveStats(SQLTransaction& trans) stmt->setUInt32(index++, GetGUIDLow()); stmt->setUInt32(index++, GetMaxHealth()); - for (uint8 i = 0; i < MAX_POWERS; ++i) + for (uint8 i = 0; i < MAX_POWERS_PER_CLASS; ++i) stmt->setUInt32(index++, GetMaxPower(Powers(i))); for (uint8 i = 0; i < MAX_STATS; ++i) @@ -20064,7 +20322,7 @@ void Player::_SaveStats(SQLTransaction& trans) stmt->setUInt32(index++, GetUInt32Value(UNIT_FIELD_ATTACK_POWER)); stmt->setUInt32(index++, GetUInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER)); stmt->setUInt32(index++, GetBaseSpellPowerBonus()); - stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_CRIT_TAKEN_SPELL)); + stmt->setUInt32(index++, GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_RESILIENCE_PLAYER_DAMAGE_TAKEN)); trans->Append(stmt); } @@ -20152,15 +20410,15 @@ void Player::SavePositionInDB(uint32 mapid, float x, float y, float z, float o, CharacterDatabase.Execute(stmt); } -void Player::SetUInt32ValueInArray(Tokenizer& tokens, uint16 index, uint32 value) +void Player::SetUInt32ValueInArray(Tokenizer& Tokenizer, uint16 index, uint32 value) { char buf[11]; snprintf(buf, 11, "%u", value); - if (index >= tokens.size()) + if (index >= Tokenizer.size()) return; - tokens[index] = buf; + Tokenizer[index] = buf; } void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair) @@ -20247,10 +20505,9 @@ void Player::SendRaidDifficulty(bool IsInGroup, int32 forcedDifficulty) GetSession()->SendPacket(&data); } -void Player::SendResetFailedNotify(uint32 mapid) +void Player::SendResetFailedNotify(uint32 /*mapid*/) { WorldPacket data(SMSG_RESET_FAILED_NOTIFY, 4); - data << uint32(mapid); GetSession()->SendPacket(&data); } @@ -20317,7 +20574,7 @@ void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) // 1: There are players offline in your party. // 2>: There are players in your party attempting to zone into an instance. */ - WorldPacket data(SMSG_INSTANCE_RESET_FAILED, 4); + WorldPacket data(SMSG_INSTANCE_RESET_FAILED, 8); data << uint32(reason); data << uint32(MapId); GetSession()->SendPacket(&data); @@ -20542,12 +20799,25 @@ void Player::TextEmote(const std::string& text) SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)); } +void Player::WhisperAddon(const std::string& text, const std::string& prefix, Player* receiver) +{ + std::string _text(text); + sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, uint32(LANG_ADDON), _text, receiver); + + if (!receiver->GetSession()->IsAddonRegistered(prefix)) + return; + + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, LANG_ADDON, this, this, text, 0, "", DEFAULT_LOCALE, prefix); + receiver->GetSession()->SendPacket(&data); +} + void Player::Whisper(const std::string& text, uint32 language, uint64 receiver) { bool isAddonMessage = language == LANG_ADDON; - if (!isAddonMessage) // if not addon data - language = LANG_UNIVERSAL; // whispers should always be readable + if (!isAddonMessage) // if not addon data + language = LANG_UNIVERSAL; // whispers should always be readable Player* rPlayer = ObjectAccessor::FindPlayer(receiver); @@ -20877,33 +21147,37 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod void Player::AddSpellMod(SpellModifier* mod, bool apply) { TC_LOG_DEBUG("spells", "Player::AddSpellMod %d", mod->spellId); - uint16 Opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; + Opcodes opcode = Opcodes((mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER); int i = 0; flag96 _mask = 0; + uint32 modTypeCount = 0; // count of mods per one mod->op + WorldPacket data(opcode); + data << uint32(1); // count of different mod->op's in packet + size_t writePos = data.wpos(); + data << uint32(modTypeCount); + data << uint8(mod->op); for (int eff = 0; eff < 96; ++eff) { - if (eff != 0 && eff%32 == 0) + if (eff != 0 && (eff % 32) == 0) _mask[i++] = 0; - _mask[i] = uint32(1) << (eff-(32*i)); + _mask[i] = uint32(1) << (eff - (32 * i)); if (mod->mask & _mask) { int32 val = 0; for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr) - { if ((*itr)->type == mod->type && (*itr)->mask & _mask) val += (*itr)->value; - } val += apply ? mod->value : -(mod->value); - WorldPacket data(Opcode, (1+1+4)); + data << uint8(eff); - data << uint8(mod->op); - data << int32(val); - SendDirectMessage(&data); + data << float(val); + ++modTypeCount; } } - + data.put<uint32>(writePos, modTypeCount); + SendDirectMessage(&data); if (apply) m_spellMods[mod->op].push_back(mod); else @@ -21330,7 +21604,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc return false; } - uint32 money = GetMoney(); + uint64 money = GetMoney(); if (npc) totalcost = (uint32)ceil(totalcost*GetReputationPriceDiscount(npc)); @@ -21343,7 +21617,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc } //Checks and preparations done, DO FLIGHT - ModifyMoney(-(int32)totalcost); + ModifyMoney(-int64(totalcost)); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1); @@ -21487,7 +21761,7 @@ void Player::InitDataForForm(bool reapplyMods) { ShapeshiftForm form = GetShapeshiftForm(); - SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(form); + SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form); if (ssEntry && ssEntry->attackSpeed) { SetAttackTime(BASE_ATTACK, ssEntry->attackSpeed); @@ -21507,7 +21781,6 @@ void Player::InitDataForForm(bool reapplyMods) break; } case FORM_BEAR: - case FORM_DIREBEAR: { if (getPowerType() != POWER_RAGE) setPowerType(POWER_RAGE); @@ -21558,10 +21831,11 @@ void Player::InitDisplayIds() inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore) { + uint32 stacks = count / pProto->BuyCount; ItemPosCountVec vDest; uint16 uiDest = 0; InventoryResult msg = bStore ? - CanStoreNewItem(bag, slot, vDest, item, pProto->BuyCount * count) : + CanStoreNewItem(bag, slot, vDest, item, count) : CanEquipNewItem(slot, uiDest, item, false); if (msg != EQUIP_ERR_OK) { @@ -21571,20 +21845,23 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c ModifyMoney(-price); - if (crItem->ExtendedCost) // case for new honor system + if (crItem->ExtendedCost) // case for new honor system { ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); ASSERT(iece); - if (iece->reqhonorpoints) - ModifyHonorPoints(-int32(iece->reqhonorpoints * count)); - - if (iece->reqarenapoints) - ModifyArenaPoints(-int32(iece->reqarenapoints * count)); + for (int i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) + { + if (iece->RequiredItem[i]) + DestroyItemCount(iece->RequiredItem[i], iece->RequiredItemCount[i] * stacks, true); + } - for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i) + for (int i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) { - if (iece->reqitem[i]) - DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true); + if (iece->RequirementFlags & (ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1 << i)) + continue; + + if (iece->RequiredCurrency[i]) + ModifyCurrency(iece->RequiredCurrency[i], -int32(iece->RequiredCurrencyCount[i] * stacks), true, true); } } @@ -21593,7 +21870,7 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c EquipNewItem(uiDest, item, true); if (it) { - uint32 new_count = pVendor->UpdateVendorItemCurrentCount(crItem, pProto->BuyCount * count); + uint32 new_count = pVendor->UpdateVendorItemCurrentCount(crItem, count); WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); data << uint64(pVendor->GetGUID()); @@ -21601,7 +21878,7 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c data << int32(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); data << uint32(count); GetSession()->SendPacket(&data); - SendNewItem(it, pProto->BuyCount * count, true, false, false); + SendNewItem(it, count, true, false, false); if (!bStore) AutoUnequipOffhandIfNeed(); @@ -21619,6 +21896,165 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c return true; } +bool Player::BuyCurrencyFromVendorSlot(uint64 vendorGuid, uint32 vendorSlot, uint32 currency, uint32 count) +{ + // cheating attempt + if (count < 1) count = 1; + + if (!IsAlive()) + return false; + + CurrencyTypesEntry const* proto = sCurrencyTypesStore.LookupEntry(currency); + if (!proto) + { + SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, currency, 0); + return false; + } + + Creature* creature = GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_VENDOR); + if (!creature) + { + TC_LOG_DEBUG("network", "WORLD: BuyCurrencyFromVendorSlot - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(vendorGuid)); + SendBuyError(BUY_ERR_DISTANCE_TOO_FAR, NULL, currency, 0); + return false; + } + + VendorItemData const* vItems = creature->GetVendorItems(); + if (!vItems || vItems->Empty()) + { + SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, currency, 0); + return false; + } + + if (vendorSlot >= vItems->GetItemCount()) + { + SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, currency, 0); + return false; + } + + VendorItem const* crItem = vItems->GetItem(vendorSlot); + // store diff item (cheating) + if (!crItem || crItem->item != currency || crItem->Type != ITEM_VENDOR_TYPE_CURRENCY) + { + SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, currency, 0); + return false; + } + + if (count % crItem->maxcount) + { + SendEquipError(EQUIP_ERR_CANT_BUY_QUANTITY, NULL, NULL); + return false; + } + + uint32 stacks = count / crItem->maxcount; + ItemExtendedCostEntry const* iece = NULL; + if (crItem->ExtendedCost) + { + iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); + if (!iece) + { + TC_LOG_ERROR("entities.player", "Currency %u have wrong ExtendedCost field value %u", currency, crItem->ExtendedCost); + return false; + } + + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) + { + if (iece->RequiredItem[i] && !HasItemCount(iece->RequiredItem[i], (iece->RequiredItemCount[i] * stacks))) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); + return false; + } + } + + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) + { + if (!iece->RequiredCurrency[i]) + continue; + + CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(iece->RequiredCurrency[i]); + if (!entry) + { + SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, currency, 0); // Find correct error + return false; + } + + if (iece->RequirementFlags & (ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1 << i)) + { + // Not implemented + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } + else if (!HasCurrency(iece->RequiredCurrency[i], (iece->RequiredCurrencyCount[i] * stacks))) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } + } + + // check for personal arena rating requirement + if (GetMaxPersonalArenaRatingRequirement(iece->RequiredArenaSlot) < iece->RequiredPersonalArenaRating) + { + // probably not the proper equip err + SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, NULL, NULL); + return false; + } + + if (iece->RequiredFactionId && uint32(GetReputationRank(iece->RequiredFactionId)) < iece->RequiredFactionStanding) + { + SendBuyError(BUY_ERR_REPUTATION_REQUIRE, creature, currency, 0); + return false; + } + + if (iece->RequirementFlags & ITEM_EXT_COST_FLAG_REQUIRE_GUILD && !GetGuildId()) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } + + if (iece->RequiredGuildLevel && iece->RequiredGuildLevel < GetGuildLevel()) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } + + if (iece->RequiredAchievement && !HasAchieved(iece->RequiredAchievement)) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } + } + else // currencies have no price defined, can only be bought with ExtendedCost + { + SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, currency, 0); + return false; + } + + ModifyCurrency(currency, count, true, true); + if (iece) + { + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) + { + if (!iece->RequiredItem[i]) + continue; + + DestroyItemCount(iece->RequiredItem[i], iece->RequiredItemCount[i] * stacks, true); + } + + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) + { + if (!iece->RequiredCurrency[i]) + continue; + + if (iece->RequirementFlags & (ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1 << i)) + continue; + + ModifyCurrency(iece->RequiredCurrency[i], -int32(iece->RequiredCurrencyCount[i]) * stacks, false, true); + } + } + + return true; +} + // Return true is the bought item has a max count to force refresh of window by caller bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot) { @@ -21703,31 +22139,48 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 if (crItem->ExtendedCost) { - ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); - if (!iece) + // Can only buy full stacks for extended cost + if (count % pProto->BuyCount) { - TC_LOG_ERROR("entities.player", "Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); + SendEquipError(EQUIP_ERR_CANT_BUY_QUANTITY, NULL, NULL); return false; } - // honor points price - if (GetHonorPoints() < (iece->reqhonorpoints * count)) + uint32 stacks = count / pProto->BuyCount; + ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); + if (!iece) { - SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL); + TC_LOG_ERROR("entities.player", "Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); return false; } - // arena points price - if (GetArenaPoints() < (iece->reqarenapoints * count)) + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) { - SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL); - return false; + if (iece->RequiredItem[i] && !HasItemCount(iece->RequiredItem[i], iece->RequiredItemCount[i] * stacks)) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); + return false; + } } - // item base price - for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i) + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) { - if (iece->reqitem[i] && !HasItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count))) + if (!iece->RequiredCurrency[i]) + continue; + + CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(iece->RequiredCurrency[i]); + if (!entry) + { + SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0); + return false; + } + + if (iece->RequirementFlags & (ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1 << i)) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } + else if (!HasCurrency(iece->RequiredCurrency[i], iece->RequiredCurrencyCount[i] * stacks)) { SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); return false; @@ -21735,12 +22188,36 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 } // check for personal arena rating requirement - if (GetMaxPersonalArenaRatingRequirement(iece->reqarenaslot) < iece->reqpersonalarenarating) + if (GetMaxPersonalArenaRatingRequirement(iece->RequiredArenaSlot) < iece->RequiredPersonalArenaRating) { // probably not the proper equip err SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, NULL, NULL); return false; } + + if (iece->RequiredFactionId && uint32(GetReputationRank(iece->RequiredFactionId)) < iece->RequiredFactionStanding) + { + SendBuyError(BUY_ERR_REPUTATION_REQUIRE, creature, item, 0); + return false; + } + + if (iece->RequirementFlags & ITEM_EXT_COST_FLAG_REQUIRE_GUILD && !GetGuildId()) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } + + if (iece->RequiredGuildLevel && iece->RequiredGuildLevel < GetGuildLevel()) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } + + if (iece->RequiredAchievement && !HasAchieved(iece->RequiredAchievement)) + { + SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); // Find correct error + return false; + } } uint32 price = 0; @@ -21757,7 +22234,10 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 // reputation discount price = uint32(floor(price * GetReputationPriceDiscount(creature))); - if (!HasEnoughMoney(price)) + if (int32 priceMod = GetTotalAuraModifier(SPELL_AURA_MOD_VENDOR_ITEMS_PRICES)) + price -= CalculatePct(price, priceMod); + + if (!HasEnoughMoney(uint64(price))) { SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, item, 0); return false; @@ -21771,9 +22251,9 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 } else if (IsEquipmentPos(bag, slot)) { - if (pProto->BuyCount * count != 1) + if (count != 1) { - SendEquipError(EQUIP_ERR_ITEM_CANT_BE_EQUIPPED, NULL, NULL); + SendEquipError(EQUIP_ERR_NOT_EQUIPPABLE, NULL, NULL); return false; } if (!_StoreOrEquipNewItem(vendorslot, item, count, bag, slot, price, pProto, creature, crItem, false)) @@ -21781,11 +22261,19 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 } else { - SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + SendEquipError(EQUIP_ERR_WRONG_SLOT, NULL, NULL); return false; } - return crItem->maxcount != 0; + if (crItem->maxcount != 0) // bought + { + if (pProto->Quality > ITEM_QUALITY_EPIC || (pProto->Quality == ITEM_QUALITY_EPIC && pProto->ItemLevel >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)])) + if (Guild* guild = GetGuild()) + guild->AddGuildNews(GUILD_NEWS_ITEM_PURCHASED, GetGUID(), 0, item); + return true; + } + + return false; } uint32 Player::GetMaxPersonalArenaRatingRequirement(uint32 minarenaslot) const @@ -21992,9 +22480,35 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite } } + // Apply SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN modifiers + // Note: This aura applies its modifiers to all cooldowns of spells with set category, not to category cooldown only + if (cat) + { + if (int32 categoryModifier = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN, cat)) + { + if (rec > 0) + rec += categoryModifier; + + if (catrec > 0) + catrec += categoryModifier; + } + + SpellCategoryEntry const* categoryEntry = sSpellCategoryStore.LookupEntry(cat); + ASSERT(categoryEntry); + if (categoryEntry->Flags & SPELL_CATEGORY_FLAG_COOLDOWN_EXPIRES_AT_MIDNIGHT) + { + tm date; + localtime_r(&curTime, &date); + catrec = catrec * DAY - (date.tm_hour * HOUR + date.tm_min * MINUTE + date.tm_sec) * IN_MILLISECONDS; + } + } + // replace negative cooldowns by 0 - if (rec < 0) rec = 0; - if (catrec < 0) catrec = 0; + if (rec < 0) + rec = 0; + + if (catrec < 0) + catrec = 0; // no cooldown after applying spell mods if (rec == 0 && catrec == 0) @@ -22099,15 +22613,15 @@ void Player::UpdatePotionCooldown(Spell* spell) m_lastPotionId = 0; } -void Player::setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana) +void Player::SetResurrectRequestData(Unit* caster, uint32 health, uint32 mana, uint32 appliedAura) { - m_resurrectGUID = guid; - m_resurrectMap = mapId; - m_resurrectX = X; - m_resurrectY = Y; - m_resurrectZ = Z; - m_resurrectHealth = health; - m_resurrectMana = mana; + ASSERT(!IsResurrectRequested()); + _resurrectionData = new ResurrectionData(); + _resurrectionData->GUID = caster->GetGUID(); + _resurrectionData->Location.WorldRelocate(*caster); + _resurrectionData->Health = health; + _resurrectionData->Mana = mana; + _resurrectionData->Aura = appliedAura; } //slot to be excluded while counting bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) @@ -22553,7 +23067,7 @@ void Player::UpdateTriggerVisibility() if (!IsInWorld()) return; - UpdateData udata; + UpdateData udata(GetMapId()); WorldPacket packet; for (ClientGUIDs::iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr) { @@ -22658,7 +23172,7 @@ void Player::InitPrimaryProfessions() SetFreePrimaryProfessions(sWorld->getIntConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)); } -bool Player::ModifyMoney(int32 amount, bool sendError /*= true*/) +bool Player::ModifyMoney(int64 amount, bool sendError /*= true*/) { if (!amount) return true; @@ -22666,10 +23180,10 @@ bool Player::ModifyMoney(int32 amount, bool sendError /*= true*/) sScriptMgr->OnPlayerMoneyChanged(this, amount); if (amount < 0) - SetMoney (GetMoney() > uint32(-amount) ? GetMoney() + amount : 0); + SetMoney(GetMoney() > uint64(-amount) ? GetMoney() + amount : 0); else { - if (GetMoney() < MAX_MONEY_AMOUNT - static_cast<uint32>(amount)) + if (GetMoney() < MAX_MONEY_AMOUNT - static_cast<uint64>(amount)) SetMoney(GetMoney() + amount); else { @@ -22682,16 +23196,16 @@ bool Player::ModifyMoney(int32 amount, bool sendError /*= true*/) return true; } -bool Player::HasEnoughMoney(int32 amount) const +bool Player::HasEnoughMoney(int64 amount) const { if (amount > 0) - return (GetMoney() >= (uint32) amount); + return (GetMoney() >= (uint64) amount); return true; } -void Player::SetMoney(uint32 value) +void Player::SetMoney(uint64 value) { - SetUInt32Value(PLAYER_FIELD_COINAGE, value); + SetUInt64Value(PLAYER_FIELD_COINAGE, value); MoneyChanged(value); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED); } @@ -22837,10 +23351,22 @@ void Player::SendInitialPacketsBeforeAddToMap() SendTalentsInfoData(false); - // SMSG_INSTANCE_DIFFICULTY - data.Initialize(SMSG_INSTANCE_DIFFICULTY, 4+4); + data.Initialize(SMSG_WORLD_SERVER_INFO, 1 + 1 + 4 + 4); + data.WriteBit(0); // HasRestrictedLevel + data.WriteBit(0); // HasRestrictedMoney + data.WriteBit(0); // IneligibleForLoot + data.FlushBits(); + //if (IneligibleForLoot) + // data << uint32(0); // EncounterMask + + data << uint8(0); // IsOnTournamentRealm + //if (HasRestrictedMoney) + // data << uint32(100000); // RestrictedMoney (starter accounts) + //if (HasRestrictedLevel) + // data << uint32(20); // RestrictedLevel (starter accounts) + + data << uint32(sWorld->GetNextWeeklyQuestsResetTime() - WEEK); // LastWeeklyReset (not instance reset) data << uint32(GetMap()->GetDifficulty()); - data << uint32(GetMap()->GetEntry()->IsDynamicDifficultyMap() && GetMap()->IsHeroic()); // Raid dynamic difficulty GetSession()->SendPacket(&data); SendInitialSpells(); @@ -22851,7 +23377,7 @@ void Player::SendInitialPacketsBeforeAddToMap() SendInitialActionButtons(); m_reputationMgr->SendInitialReputations(); - m_achievementMgr->SendAllAchievementData(); + m_achievementMgr->SendAllAchievementData(this); SendEquipmentSetList(); @@ -22868,6 +23394,7 @@ void Player::SendInitialPacketsBeforeAddToMap() // SMSG_UPDATE_WORLD_STATE // SMSG_POWER_UPDATE + SendCurrencies(); SetMover(this); } @@ -22883,6 +23410,8 @@ void Player::SendInitialPacketsAfterAddToMap() ResetTimeSync(); SendTimeSync(); + GetSession()->SendLoadCUFProfiles(); + CastSpell(this, 836, true); // LOGINEFFECT // set some aura effects that send packet to player client after add player to map @@ -22902,16 +23431,11 @@ void Player::SendInitialPacketsAfterAddToMap() } if (HasAuraType(SPELL_AURA_MOD_STUN)) - SetMovement(MOVE_ROOT); + SetRooted(true); // manual send package (have code in HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true); that must not be re-applied. if (HasAuraType(SPELL_AURA_MOD_ROOT)) - { - WorldPacket data2(SMSG_FORCE_MOVE_ROOT, 10); - data2.append(GetPackGUID()); - data2 << (uint32)2; - SendMessageToSet(&data2, true); - } + SetRooted(true, true); SendAurasForTarget(this); SendEnchantmentDurations(); // must be after add to map @@ -22947,18 +23471,8 @@ void Player::SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 { WorldPacket data(SMSG_TRANSFER_ABORTED, 4+2); data << uint32(mapid); - data << uint8(reason); // transfer abort reason - switch (reason) - { - case TRANSFER_ABORT_INSUF_EXPAN_LVL: - case TRANSFER_ABORT_DIFFICULTY: - case TRANSFER_ABORT_UNIQUE_MESSAGE: - // these are the ONLY cases that have an extra argument in the packet!!! - data << uint8(arg); - break; - default: - break; - } + data << uint8(reason); // transfer abort reason + data << uint8(arg); GetSession()->SendPacket(&data); } @@ -23382,6 +23896,7 @@ void Player::ResetWeeklyQuestStatus() m_weeklyquests.clear(); // DB data deleted in caller m_WeeklyQuestChanged = false; + } void Player::ResetSeasonalQuestStatus(uint16 event_id) @@ -23608,7 +24123,7 @@ void Player::UpdateForQuestWorldObjects() if (m_clientGUIDs.empty()) return; - UpdateData udata; + UpdateData udata(GetMapId()); WorldPacket packet; for (ClientGUIDs::iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr) { @@ -23889,7 +24404,7 @@ uint32 Player::GetResurrectionSpellId() } // Used in triggers for check "Only to targets that grant experience or honor" req -bool Player::isHonorOrXPTarget(Unit* victim) const +bool Player::isHonorOrXPTarget(Unit const* victim) const { uint8 v_level = victim->getLevel(); uint8 k_grey = Trinity::XP::GetGrayLevel(getLevel()); @@ -23898,11 +24413,11 @@ bool Player::isHonorOrXPTarget(Unit* victim) const if (v_level <= k_grey) return false; - if (victim->GetTypeId() == TYPEID_UNIT) + if (Creature const* const creature = victim->ToCreature()) { - if (victim->ToCreature()->IsTotem() || - victim->ToCreature()->IsPet() || - victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) + if (creature->IsTotem() || + creature->IsPet() || + creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) return false; } return true; @@ -24009,23 +24524,12 @@ bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const return pOther->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE); } -uint32 Player::GetBaseWeaponSkillValue(WeaponAttackType attType) const -{ - Item* item = GetWeaponForAttack(attType, true); - - // unarmed only with base attack - if (attType != BASE_ATTACK && !item) - return 0; - - // weapon skill or (unarmed for base attack) - uint32 skill = item ? item->GetSkill() : uint32(SKILL_UNARMED); - return GetBaseSkillValue(skill); -} - void Player::ResurrectUsingRequestData() { /// Teleport before resurrecting by player, otherwise the player might get attacked from creatures near his corpse - TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation()); + float x, y, z, o; + _resurrectionData->Location.GetPosition(x, y, z, o); + TeleportTo(_resurrectionData->Location.GetMapId(), x, y, z, o); if (IsBeingTeleported()) { @@ -24035,19 +24539,23 @@ void Player::ResurrectUsingRequestData() ResurrectPlayer(0.0f, false); - if (GetMaxHealth() > m_resurrectHealth) - SetHealth(m_resurrectHealth); + if (GetMaxHealth() > _resurrectionData->Health) + SetHealth(_resurrectionData->Health); else SetFullHealth(); - if (GetMaxPower(POWER_MANA) > m_resurrectMana) - SetPower(POWER_MANA, m_resurrectMana); + if (uint32(GetMaxPower(POWER_MANA)) > _resurrectionData->Mana) + SetPower(POWER_MANA, _resurrectionData->Mana); else SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); SetPower(POWER_RAGE, 0); - SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); + SetPower(POWER_FOCUS, GetMaxPower(POWER_FOCUS)); + SetPower(POWER_ECLIPSE, 0); + + if (uint32 aura = _resurrectionData->Aura) + CastSpell(this, aura, true, NULL, NULL, _resurrectionData->GUID); SpawnCorpseBones(); } @@ -24071,6 +24579,29 @@ void Player::SetMover(Unit* target) m_mover->m_movedPlayer = NULL; m_mover = target; m_mover->m_movedPlayer = this; + + ObjectGuid guid = target->GetGUID(); + + WorldPacket data(SMSG_MOVE_SET_ACTIVE_MOVER, 9); + data.WriteBit(guid[5]); + data.WriteBit(guid[7]); + data.WriteBit(guid[3]); + data.WriteBit(guid[6]); + data.WriteBit(guid[0]); + data.WriteBit(guid[4]); + data.WriteBit(guid[1]); + data.WriteBit(guid[2]); + + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[4]); + + SendDirectMessage(&data); } void Player::UpdateZoneDependentAuras(uint32 newZone) @@ -24551,32 +25082,27 @@ uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 n void Player::InitGlyphsForLevel() { - for (uint32 i = 0; i < sGlyphSlotStore.GetNumRows(); ++i) + uint32 slot = 0; + for (uint32 i = 0; i < sGlyphSlotStore.GetNumRows() && slot < MAX_GLYPH_SLOT_INDEX; ++i) if (GlyphSlotEntry const* gs = sGlyphSlotStore.LookupEntry(i)) - if (gs->Order) - SetGlyphSlot(gs->Order - 1, gs->Id); + SetGlyphSlot(slot++, gs->Id); uint8 level = getLevel(); - uint32 value = 0; + uint32 slotMask = 0; - // 0x3F = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 for 80 level - if (level >= 15) - value |= (0x01 | 0x02); - if (level >= 30) - value |= 0x08; + if (level >= 25) + slotMask |= 0x01 | 0x02 | 0x40; if (level >= 50) - value |= 0x04; - if (level >= 70) - value |= 0x10; - if (level >= 80) - value |= 0x20; + slotMask |= 0x04 | 0x08 | 0x80; + if (level >= 75) + slotMask |= 0x10 | 0x20 | 0x100; - SetUInt32Value(PLAYER_GLYPHS_ENABLED, value); + SetUInt32Value(PLAYER_GLYPHS_ENABLED, slotMask); } void Player::SetGlyph(uint8 slot, uint32 glyph) { - m_Glyphs[m_activeSpec][slot] = glyph; + _talentMgr->SpecInfo[GetActiveSpec()].Glyphs[slot] = glyph; SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph); } @@ -24686,17 +25212,25 @@ void Player::UpdateCharmedAI() } } -uint32 Player::GetRuneBaseCooldown(uint8 index) +uint32 Player::GetRuneTypeBaseCooldown(RuneType runeType) const { - uint8 rune = GetBaseRune(index); - uint32 cooldown = RUNE_BASE_COOLDOWN; + float cooldown = RUNE_BASE_COOLDOWN; + float hastePct = 0.0f; AuraEffectList const& regenAura = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT); for (AuraEffectList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i) - { - if ((*i)->GetMiscValue() == POWER_RUNE && (*i)->GetMiscValueB() == rune) - cooldown = cooldown*(100-(*i)->GetAmount())/100; - } + if ((*i)->GetMiscValue() == POWER_RUNES && (*i)->GetMiscValueB() == runeType) + cooldown *= 1.0f - (*i)->GetAmount() / 100.0f; + + // Runes cooldown are now affected by player's haste from equipment ... + hastePct = GetRatingBonusValue(CR_HASTE_MELEE); + + // ... and some auras. + hastePct += GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_HASTE); + hastePct += GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_HASTE_2); + hastePct += GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_HASTE_3); + + cooldown *= 1.0f - (hastePct / 100.0f); return cooldown; } @@ -24807,7 +25341,7 @@ void Player::InitRunes() } for (uint8 i = 0; i < NUM_RUNE_TYPES; ++i) - SetFloatValue(PLAYER_RUNE_REGEN_1 + i, 0.1f); + SetFloatValue(PLAYER_RUNE_REGEN_1 + i, 0.1f); // set a base regen timer equal to 10 sec } bool Player::IsBaseRuneSlotsOnCooldown(RuneType runeType) const @@ -24856,7 +25390,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) if (!item) { - SendEquipError(EQUIP_ERR_ALREADY_LOOTED, NULL, NULL); + SendEquipError(EQUIP_ERR_LOOT_GONE, NULL, NULL); return; } @@ -24912,9 +25446,14 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) --loot->unlootedCount; + if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item->itemid)) + if (proto->Quality > ITEM_QUALITY_EPIC || (proto->Quality == ITEM_QUALITY_EPIC && proto->ItemLevel >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)])) + if (Guild* guild = GetGuild()) + guild->AddGuildNews(GUILD_NEWS_ITEM_LOOTED, GetGUID(), 0, item->itemid); + SendNewItem(newitem, uint32(item->count), false, false, true); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, item->itemid, item->count, loot->loot_type); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); // LootItem is being removed (looted) from the container, delete it from the DB. @@ -24928,16 +25467,30 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) uint32 Player::CalculateTalentsPoints() const { - uint32 base_talent = getLevel() < 10 ? 0 : getLevel()-9; + // this dbc file has entries only up to level 100 + NumTalentsAtLevelEntry const* count = sNumTalentsAtLevelStore.LookupEntry(std::min<uint32>(getLevel(), 100)); + if (!count) + return 0; + + float baseForLevel = count->Talents; if (getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609) - return uint32(base_talent * sWorld->getRate(RATE_TALENT)); + return uint32(baseForLevel * sWorld->getRate(RATE_TALENT)); - uint32 talentPointsForLevel = getLevel() < 56 ? 0 : getLevel() - 55; - talentPointsForLevel += m_questRewardTalentCount; + // Death Knight starting level + // hardcoded here - number of quest awarded talents is equal to number of talents any other class would have at level 55 + if (getLevel() < 55) + return 0; - if (talentPointsForLevel > base_talent) - talentPointsForLevel = base_talent; + NumTalentsAtLevelEntry const* dkBase = sNumTalentsAtLevelStore.LookupEntry(55); + if (!dkBase) + return 0; + + float talentPointsForLevel = count->Talents - dkBase->Talents; + talentPointsForLevel += float(GetQuestRewardedTalentCount()); + + if (talentPointsForLevel > baseForLevel) + talentPointsForLevel = baseForLevel; return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT)); } @@ -24963,6 +25516,7 @@ void Player::_LoadSkills(PreparedQueryResult result) // SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = '%u'", GUID_LOPART(m_guid)); uint32 count = 0; + uint8 professionCount = 0; if (result) { do @@ -25011,23 +25565,32 @@ void Player::_LoadSkills(PreparedQueryResult result) continue; } - uint16 skillStep = 0; - if (SkillTiersEntry const* skillTier = sSkillTiersStore.LookupEntry(rcEntry->SkillTier)) + uint16 field = count / 2; + uint8 offset = count & 1; + + SetUInt16Value(PLAYER_SKILL_LINEID_0 + field, offset, skill); + uint16 step = 0; + + SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(rcEntry->SkillId); + if (skillLine) { - for (uint32 i = 0; i < MAX_SKILL_STEP; ++i) + if (skillLine->categoryId == SKILL_CATEGORY_SECONDARY) + step = max / 75; + + if (skillLine->categoryId == SKILL_CATEGORY_PROFESSION) { - if (skillTier->MaxSkill[skillStep] == max) - { - skillStep = i + 1; - break; - } + step = max / 75; + + if (professionCount < 2) + SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + professionCount++, skill); } } - SetUInt32Value(PLAYER_SKILL_INDEX(count), MAKE_PAIR32(skill, skillStep)); - - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(count), MAKE_SKILL_VALUE(value, max)); - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count), 0); + SetUInt16Value(PLAYER_SKILL_STEP_0 + field, offset, step); + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, value); + SetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset, max); + SetUInt16Value(PLAYER_SKILL_MODIFIER_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_TALENT_0 + field, offset, 0); mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(count, SKILL_UNCHANGED))); @@ -25046,32 +25609,19 @@ void Player::_LoadSkills(PreparedQueryResult result) for (; count < PLAYER_MAX_SKILLS; ++count) { - SetUInt32Value(PLAYER_SKILL_INDEX(count), 0); - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(count), 0); - SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count), 0); - } + uint16 field = count / 2; + uint8 offset = count & 1; if (HasSkill(SKILL_FIST_WEAPONS)) SetSkill(SKILL_FIST_WEAPONS, 0, GetSkillValue(SKILL_UNARMED), GetMaxSkillValueForLevel()); -} -uint32 Player::GetPhaseMaskForSpawn() const -{ - uint32 phase = PHASEMASK_NORMAL; - if (!IsGameMaster()) - phase = GetPhaseMask(); - else - { - AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE); - if (!phases.empty()) - phase = phases.front()->GetMiscValue(); + SetUInt16Value(PLAYER_SKILL_LINEID_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_STEP_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_MAX_RANK_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_MODIFIER_0 + field, offset, 0); + SetUInt16Value(PLAYER_SKILL_TALENT_0 + field, offset, 0); } - - // some aura phases include 1 normal map in addition to phase itself - if (uint32 n_phase = phase & ~PHASEMASK_NORMAL) - return n_phase; - - return PHASEMASK_NORMAL; } InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) const @@ -25114,7 +25664,7 @@ InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 { // there is an equip limit on this item if (HasItemOrGemWithIdEquipped(itemProto->ItemId, 1, except_slot)) - return EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE; + return EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE; } // check unique-equipped limit @@ -25122,12 +25672,12 @@ InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 { ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(itemProto->ItemLimitCategory); if (!limitEntry) - return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + return EQUIP_ERR_NOT_EQUIPPABLE; // NOTE: limitEntry->mode not checked because if item have have-limit then it applied and to equip case if (limit_count > limitEntry->maxCount) - return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED; + return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS; // there is an equip limit on this item if (HasItemOrGemWithLimitCategoryEquipped(itemProto->ItemLimitCategory, limitEntry->maxCount - limit_count + 1, except_slot)) @@ -25147,7 +25697,7 @@ void Player::HandleFall(MovementInfo const& movementInfo) { // calculate total z distance of the fall float z_diff = m_lastFallZ - movementInfo.pos.GetPositionZ(); - //TC_LOG_DEBUG("zDiff = %f", z_diff); + //TC_LOG_DEBUG("misc", "zDiff = %f", z_diff); //Players with low fall distance, Feather Fall or physical immunity (charges used) are ignored // 14.57 can be calculated by resolving damageperc formula below to 0 @@ -25189,7 +25739,7 @@ void Player::HandleFall(MovementInfo const& movementInfo) } //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction - TC_LOG_DEBUG("entities.player", "FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d", movementInfo.pos.GetPositionZ(), height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall); + TC_LOG_DEBUG("entities.player", "FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d", movementInfo.pos.GetPositionZ(), height, GetPositionZ(), movementInfo.jump.fallTime, height, damage, safe_fall); } } RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_LANDING); // No fly zone - Parachute @@ -25202,7 +25752,12 @@ void Player::ResetAchievements() void Player::SendRespondInspectAchievements(Player* player) const { - m_achievementMgr->SendRespondInspectAchievements(player); + m_achievementMgr->SendAchievementInfo(player); +} + +uint32 Player::GetAchievementPoints() const +{ + return m_achievementMgr->GetAchievementPoints(); } bool Player::HasAchieved(uint32 achievementId) const @@ -25220,44 +25775,54 @@ void Player::RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 e m_achievementMgr->RemoveTimedAchievement(type, entry); } -void Player::ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, bool evenIfCriteriaComplete /* = false*/) +void Player::ResetAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, bool evenIfCriteriaComplete /* = false*/) { m_achievementMgr->ResetAchievementCriteria(type, miscValue1, miscValue2, evenIfCriteriaComplete); } -void Player::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, Unit* unit /*= NULL*/) +void Player::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit* unit /*= NULL*/) { - m_achievementMgr->UpdateAchievementCriteria(type, miscValue1, miscValue2, unit); + m_achievementMgr->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); + Guild* guild = sGuildMgr->GetGuildById(GetGuildId()); + if (!guild) + return; + + // Update only individual achievement criteria here, otherwise we may get multiple updates + // from a single boss kill + if (sAchievementMgr->IsGroupCriteriaType(type)) + return; + + guild->UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); } void Player::CompletedAchievement(AchievementEntry const* entry) { - m_achievementMgr->CompletedAchievement(entry); + m_achievementMgr->CompletedAchievement(entry, this); } -void Player::LearnTalent(uint32 talentId, uint32 talentRank) +bool Player::LearnTalent(uint32 talentId, uint32 talentRank) { uint32 CurTalentPoints = GetFreeTalentPoints(); if (CurTalentPoints == 0) - return; + return false; if (talentRank >= MAX_TALENT_RANK) - return; + return false; TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); if (!talentInfo) - return; + return false; TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); if (!talentTabInfo) - return; + return false; // prevent learn talent for different class (cheating) if ((getClassMask() & talentTabInfo->ClassMask) == 0) - return; + return false; // find current max talent rank (0~5) uint8 curtalent_maxrank = 0; // 0 = not learned any rank @@ -25272,11 +25837,11 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) // we already have same or higher talent rank learned if (curtalent_maxrank >= (talentRank + 1)) - return; + return false; // check if we have enough talent points if (CurTalentPoints < (talentRank - curtalent_maxrank + 1)) - return; + return false; // Check if it requires another talent if (talentInfo->DependsOn > 0) @@ -25291,33 +25856,32 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) hasEnoughRank = true; } if (!hasEnoughRank) - return; + return false; } } // Find out how many points we have in this field uint32 spentPoints = 0; - + uint32 primaryTreeTalents = 0; uint32 tTab = talentInfo->TalentTab; - if (talentInfo->Row > 0) + bool isMainTree = GetPrimaryTalentTree(GetActiveSpec()) == tTab || !GetPrimaryTalentTree(GetActiveSpec()); + + if (talentInfo->Row > 0 || !isMainTree) { - uint32 numRows = sTalentStore.GetNumRows(); - for (uint32 i = 0; i < numRows; i++) // Loop through all talents. + for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++) // Loop through all talents. { - // Someday, someone needs to revamp - const TalentEntry* tmpTalent = sTalentStore.LookupEntry(i); - if (tmpTalent) // the way talents are tracked + if (TalentEntry const* tmpTalent = sTalentStore.LookupEntry(i)) // Someday, someone needs to revamp the way talents are tracked { - if (tmpTalent->TalentTab == tTab) + for (uint8 rank = 0; rank < MAX_TALENT_RANK; rank++) { - for (uint8 rank = 0; rank < MAX_TALENT_RANK; rank++) + if (tmpTalent->RankID[rank] != 0) { - if (tmpTalent->RankID[rank] != 0) + if (HasSpell(tmpTalent->RankID[rank])) { - if (HasSpell(tmpTalent->RankID[rank])) - { + if (tmpTalent->TalentTab == tTab) spentPoints += (rank + 1); - } + if (tmpTalent->TalentTab == GetPrimaryTalentTree(GetActiveSpec())) + primaryTreeTalents += (rank + 1); } } } @@ -25327,28 +25891,49 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) // not have required min points spent in talent tree if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK)) - return; + return false; + + // player has not spent 31 talents in main tree before attempting to learn other tree's talents + if (!isMainTree && primaryTreeTalents < REQ_PRIMARY_TREE_TALENTS) + return false; // spell not set in talent.dbc uint32 spellid = talentInfo->RankID[talentRank]; if (spellid == 0) { TC_LOG_ERROR("entities.player", "Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank); - return; + return false; } // already known if (HasSpell(spellid)) - return; + return false; // learn! (other talent ranks will unlearned at learning) LearnSpell(spellid, false); - AddTalent(spellid, m_activeSpec, true); + AddTalent(spellid, GetActiveSpec(), true); - TC_LOG_INFO("entities.player", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, m_activeSpec); + TC_LOG_INFO("misc", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, GetActiveSpec()); + + // set talent tree for player + if (!GetPrimaryTalentTree(GetActiveSpec())) + { + SetPrimaryTalentTree(GetActiveSpec(), talentInfo->TalentTab); + std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(talentInfo->TalentTab); + if (specSpells) + for (size_t i = 0; i < specSpells->size(); ++i) + LearnSpell(specSpells->at(i), false); + + if (CanUseMastery()) + for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) + if (SpellInfo const* masterySpell = sSpellMgr->GetSpellInfo(talentTabInfo->MasterySpellId[i])) + if (masterySpell->IsPassive() && IsNeedCastPassiveSpellAtLearn(masterySpell)) + CastSpell(this, masterySpell->Id, true); + } // update free talent points SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1)); + return true; } void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank) @@ -25489,13 +26074,13 @@ void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank) void Player::AddKnownCurrency(uint32 itemId) { if (CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemId)) - SetFlag64(PLAYER_FIELD_KNOWN_CURRENCIES, (1LL << (ctEntry->BitIndex-1))); + SetFlag64(0, (1LL << (ctEntry->ID-1))); } void Player::UpdateFallInformationIfNeed(MovementInfo const& minfo, uint16 opcode) { - if (m_lastFallTime >= minfo.fallTime || m_lastFallZ <= minfo.pos.GetPositionZ() || opcode == MSG_MOVE_FALL_LAND) - SetFallInformation(minfo.fallTime, minfo.pos.GetPositionZ()); + if (m_lastFallTime >= minfo.jump.fallTime || m_lastFallZ <= minfo.pos.GetPositionZ() || opcode == MSG_MOVE_FALL_LAND) + SetFallInformation(minfo.jump.fallTime, minfo.pos.GetPositionZ()); } void Player::UnsummonPetTemporaryIfAny() @@ -25563,17 +26148,18 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const void Player::BuildPlayerTalentsInfoData(WorldPacket* data) { *data << uint32(GetFreeTalentPoints()); // unspentTalentPoints - *data << uint8(m_specsCount); // talent group count (0, 1 or 2) - *data << uint8(m_activeSpec); // talent group index (0 or 1) + *data << uint8(GetSpecsCount()); // talent group count (0, 1 or 2) + *data << uint8(GetActiveSpec()); // talent group index (0 or 1) - if (m_specsCount) + if (GetSpecsCount()) { - if (m_specsCount > MAX_TALENT_SPECS) - m_specsCount = MAX_TALENT_SPECS; + if (GetSpecsCount() > MAX_TALENT_SPECS) + SetSpecsCount(MAX_TALENT_SPECS); // loop through all specs (only 1 for now) - for (uint32 specIdx = 0; specIdx < m_specsCount; ++specIdx) + for (uint8 specIdx = 0; specIdx < GetSpecsCount(); ++specIdx) { + *data << uint32(GetPrimaryTalentTree(specIdx)); uint8 talentIdCount = 0; size_t pos = data->wpos(); *data << uint8(talentIdCount); // [PH], talentIdCount @@ -25622,7 +26208,7 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket* data) *data << uint8(MAX_GLYPH_SLOT_INDEX); // glyphs count for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) - *data << uint16(m_Glyphs[specIdx][i]); // GlyphProperties.dbc + *data << uint16(GetGlyph(specIdx, i)); // GlyphProperties.dbc } } } @@ -25933,6 +26519,39 @@ void Player::SendClearCooldown(uint32 spell_id, Unit* target) SendDirectMessage(&data); } +void Player::SendClearAllCooldowns(Unit* target) +{ + uint32 spellCount = m_spellCooldowns.size(); + ObjectGuid guid = target ? target->GetGUID() : 0; + + WorldPacket data(SMSG_CLEAR_COOLDOWNS, 4+8); + data.WriteBit(guid[1]); + data.WriteBit(guid[3]); + data.WriteBit(guid[6]); + data.WriteBits(spellCount, 24); // Spell Count + data.WriteBit(guid[7]); + data.WriteBit(guid[5]); + data.WriteBit(guid[2]); + data.WriteBit(guid[4]); + data.WriteBit(guid[0]); + + data.FlushBits(); + + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[3]); + for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr) + data << uint32(itr->first); // Spell ID + + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[6]); + + SendDirectMessage(&data); +} + void Player::ResetMap() { // this may be called during Map::Update @@ -25953,7 +26572,7 @@ void Player::SetMap(Map* map) void Player::_LoadGlyphs(PreparedQueryResult result) { - // SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 from character_glyphs WHERE guid = '%u' + // SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = '%u' if (!result) return; @@ -25962,15 +26581,11 @@ void Player::_LoadGlyphs(PreparedQueryResult result) Field* fields = result->Fetch(); uint8 spec = fields[0].GetUInt8(); - if (spec >= m_specsCount) + if (spec >= GetSpecsCount()) continue; - m_Glyphs[spec][0] = fields[1].GetUInt16(); - m_Glyphs[spec][1] = fields[2].GetUInt16(); - m_Glyphs[spec][2] = fields[3].GetUInt16(); - m_Glyphs[spec][3] = fields[4].GetUInt16(); - m_Glyphs[spec][4] = fields[5].GetUInt16(); - m_Glyphs[spec][5] = fields[6].GetUInt16(); + for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) + _talentMgr->SpecInfo[spec].Glyphs[i] = fields[i + 1].GetUInt16(); } while (result->NextRow()); } @@ -25982,7 +26597,7 @@ void Player::_SaveGlyphs(SQLTransaction& trans) trans->Append(stmt); - for (uint8 spec = 0; spec < m_specsCount; ++spec) + for (uint8 spec = 0; spec < GetSpecsCount(); ++spec) { uint8 index = 0; @@ -25992,7 +26607,7 @@ void Player::_SaveGlyphs(SQLTransaction& trans) stmt->setUInt8(index++, spec); for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) - stmt->setUInt16(index++, uint16(m_Glyphs[spec][i])); + stmt->setUInt16(index++, uint16(GetGlyph(spec, i))); trans->Append(stmt); } @@ -26015,7 +26630,7 @@ void Player::_SaveTalents(SQLTransaction& trans) for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) { - for (PlayerTalentMap::iterator itr = m_talents[i]->begin(); itr != m_talents[i]->end();) + for (PlayerTalentMap::iterator itr = GetTalentMap(i)->begin(); itr != GetTalentMap(i)->end();) { if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED) { @@ -26038,7 +26653,7 @@ void Player::_SaveTalents(SQLTransaction& trans) if (itr->second->state == PLAYERSPELL_REMOVED) { delete itr->second; - m_talents[i]->erase(itr++); + GetTalentMap(i)->erase(itr++); } else { @@ -26055,7 +26670,7 @@ void Player::UpdateSpecCount(uint8 count) if (curCount == count) return; - if (m_activeSpec >= count) + if (GetActiveSpec() >= count) ActivateSpec(0); SQLTransaction trans = CharacterDatabase.BeginTransaction(); @@ -26082,11 +26697,10 @@ void Player::UpdateSpecCount(uint8 count) _SaveActions(trans); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC); - stmt->setUInt8(0, m_activeSpec); + stmt->setUInt8(0, GetActiveSpec()); stmt->setUInt32(1, GetGUIDLow()); trans->Append(stmt); - m_activeSpec = 0; } CharacterDatabase.CommitTransaction(trans); @@ -26165,10 +26779,25 @@ void Player::ActivateSpec(uint8 spec) } } + // Remove spec specific spells + for (uint32 i = 0; i < MAX_TALENT_TABS; ++i) + { + uint32 const* talentTabs = GetTalentTabPages(getClass()); + std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(talentTabs[i]); + if (specSpells) + for (size_t i = 0; i < specSpells->size(); ++i) + RemoveSpell(specSpells->at(i), true); + + TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabs[i]); + for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) + if (uint32 mastery = talentTabInfo->MasterySpellId[i]) + RemoveSpell(mastery, true); + } + // set glyphs for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot) // remove secondary glyph - if (uint32 oldglyph = m_Glyphs[m_activeSpec][slot]) + if (uint32 oldglyph = GetGlyph(GetActiveSpec(), slot)) if (GlyphPropertiesEntry const* old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph)) RemoveAurasDueToSpell(old_gp->SpellId); @@ -26198,7 +26827,7 @@ void Player::ActivateSpec(uint8 spec) if (talentInfo->RankID[rank] == 0) continue; // if the talent can be found in the newly activated PlayerTalentMap - if (HasTalent(talentInfo->RankID[rank], m_activeSpec)) + if (HasTalent(talentInfo->RankID[rank], GetActiveSpec())) { LearnSpell(talentInfo->RankID[rank], false); // add the talent to the PlayerSpellMap spentTalents += (rank + 1); // increment the spentTalents count @@ -26206,10 +26835,21 @@ void Player::ActivateSpec(uint8 spec) } } + std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(GetPrimaryTalentTree(GetActiveSpec())); + if (specSpells) + for (size_t i = 0; i < specSpells->size(); ++i) + LearnSpell(specSpells->at(i), false); + + if (CanUseMastery()) + if (TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(GetPrimaryTalentTree(GetActiveSpec()))) + for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) + if (uint32 mastery = talentTabInfo->MasterySpellId[i]) + LearnSpell(mastery, false); + // set glyphs for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot) { - uint32 glyph = m_Glyphs[m_activeSpec][slot]; + uint32 glyph = GetGlyph(GetActiveSpec(), slot); // apply primary glyph if (glyph) @@ -26219,13 +26859,13 @@ void Player::ActivateSpec(uint8 spec) SetGlyph(slot, glyph); } - m_usedTalentCount = spentTalents; + SetUsedTalentCount(spentTalents); InitTalentForLevel(); { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC); stmt->setUInt32(0, GetGUIDLow()); - stmt->setUInt8(1, m_activeSpec); + stmt->setUInt8(1, GetActiveSpec()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) _LoadActions(result); } @@ -26237,11 +26877,13 @@ void Player::ActivateSpec(uint8 spec) SetPower(POWER_MANA, 0); // Mana must be 0 even if it isn't the active power type. SetPower(pw, 0); + + if (!sTalentTabStore.LookupEntry(GetPrimaryTalentTree(GetActiveSpec()))) + ResetTalents(true); } void Player::ResetTimeSync() { - m_timeSyncCounter = 0; m_timeSyncTimer = 0; m_timeSyncClient = 0; m_timeSyncServer = getMSTime(); @@ -26249,13 +26891,18 @@ void Player::ResetTimeSync() void Player::SendTimeSync() { + m_timeSyncQueue.push(m_movementCounter++); + WorldPacket data(SMSG_TIME_SYNC_REQ, 4); - data << uint32(m_timeSyncCounter++); + data << uint32(m_timeSyncQueue.back()); GetSession()->SendPacket(&data); // Schedule next sync in 10 sec m_timeSyncTimer = 10000; m_timeSyncServer = getMSTime(); + + if (m_timeSyncQueue.size() > 3) + TC_LOG_ERROR("network", "Not received CMSG_TIME_SYNC_RESP for over 30 seconds from player %u (%s), possible cheater", GetGUIDLow(), GetName().c_str()); } void Player::SetReputation(uint32 factionentry, uint32 value) @@ -26267,9 +26914,9 @@ uint32 Player::GetReputation(uint32 factionentry) const return GetReputationMgr().GetReputation(sFactionStore.LookupEntry(factionentry)); } -std::string const& Player::GetGuildName() +std::string Player::GetGuildName() { - return sGuildMgr->GetGuildById(GetGuildId())->GetName(); + return GetGuildId() ? sGuildMgr->GetGuildById(GetGuildId())->GetName() : ""; } void Player::SendDuelCountdown(uint32 counter) @@ -26318,18 +26965,51 @@ void Player::SendRefundInfo(Item* item) return; } + ObjectGuid guid = item->GetGUID(); WorldPacket data(SMSG_ITEM_REFUND_INFO_RESPONSE, 8+4+4+4+4*4+4*4+4+4); - data << uint64(item->GetGUID()); // item guid - data << uint32(item->GetPaidMoney()); // money cost - data << uint32(iece->reqhonorpoints); // honor point cost - data << uint32(iece->reqarenapoints); // arena point cost - for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i) // item cost data + data.WriteBit(guid[3]); + data.WriteBit(guid[5]); + data.WriteBit(guid[7]); + data.WriteBit(guid[6]); + data.WriteBit(guid[2]); + data.WriteBit(guid[4]); + data.WriteBit(guid[0]); + data.WriteBit(guid[1]); + data.FlushBits(); + + data.WriteByteSeq(guid[7]); + data << uint32(GetTotalPlayedTime() - item->GetPlayedTime()); + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) // item cost data { - data << uint32(iece->reqitem[i]); - data << uint32(iece->reqitemcount[i]); + data << uint32(iece->RequiredItemCount[i]); + data << uint32(iece->RequiredItem[i]); } + + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[2]); + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) // currency cost data + { + if (iece->RequirementFlags & (ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1 << i)) + { + data << uint32(0); + data << uint32(0); + continue; + } + + CurrencyTypesEntry const* currencyType = sCurrencyTypesStore.LookupEntry(iece->RequiredCurrency[i]); + uint32 precision = (currencyType && currencyType->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1; + + data << uint32(iece->RequiredCurrencyCount[i] / precision); + data << uint32(iece->RequiredCurrency[i]); + } + + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[5]); data << uint32(0); - data << uint32(GetTotalPlayedTime() - item->GetPlayedTime()); + data.WriteByteSeq(guid[0]); + data << uint32(item->GetPaidMoney()); // money cost GetSession()->SendPacket(&data); } @@ -26356,6 +27036,61 @@ bool Player::AddItem(uint32 itemId, uint32 count) return true; } +void Player::SendItemRefundResult(Item* item, ItemExtendedCostEntry const* iece, uint8 error) +{ + ObjectGuid guid = item->GetGUID(); + WorldPacket data(SMSG_ITEM_REFUND_RESULT, 1 + 1 + 8 + 4*8 + 4 + 4*8 + 1); + data.WriteBit(guid[4]); + data.WriteBit(guid[5]); + data.WriteBit(guid[1]); + data.WriteBit(guid[6]); + data.WriteBit(guid[7]); + data.WriteBit(guid[0]); + data.WriteBit(guid[3]); + data.WriteBit(guid[2]); + data.WriteBit(!error); + data.WriteBit(item->GetPaidMoney() > 0); + data.FlushBits(); + if (!error) + { + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) + { + if (iece->RequirementFlags & (ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1 << i)) + { + data << uint32(0); + data << uint32(0); + continue; + } + + CurrencyTypesEntry const* currencyType = sCurrencyTypesStore.LookupEntry(iece->RequiredCurrency[i]); + uint32 precision = (currencyType && currencyType->Flags & CURRENCY_FLAG_HIGH_PRECISION) ? CURRENCY_PRECISION : 1; + + data << uint32(iece->RequiredCurrencyCount[i] / precision); + data << uint32(iece->RequiredCurrency[i]); + } + + data << uint32(item->GetPaidMoney()); // money cost + + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) // item cost data + { + data << uint32(iece->RequiredItemCount[i]); + data << uint32(iece->RequiredItem[i]); + } + } + + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[5]); + + data << uint8(error); // error code + GetSession()->SendPacket(&data); +} + void Player::RefundItem(Item* item) { if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) @@ -26367,10 +27102,7 @@ void Player::RefundItem(Item* item) if (item->IsRefundExpired()) // item refund has expired { item->SetNotRefundable(this); - WorldPacket data(SMSG_ITEM_REFUND_RESULT, 8+4); - data << uint64(item->GetGUID()); // Guid - data << uint32(10); // Error! - GetSession()->SendPacket(&data); + SendItemRefundResult(item, NULL, 10); return; } @@ -26389,10 +27121,10 @@ void Player::RefundItem(Item* item) } bool store_error = false; - for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i) + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) { - uint32 count = iece->reqitemcount[i]; - uint32 itemid = iece->reqitem[i]; + uint32 count = iece->RequiredItemCount[i]; + uint32 itemid = iece->RequiredItem[i]; if (count && itemid) { @@ -26408,25 +27140,11 @@ void Player::RefundItem(Item* item) if (store_error) { - WorldPacket data(SMSG_ITEM_REFUND_RESULT, 8+4); - data << uint64(item->GetGUID()); // Guid - data << uint32(10); // Error! - GetSession()->SendPacket(&data); + SendItemRefundResult(item, iece, 10); return; } - WorldPacket data(SMSG_ITEM_REFUND_RESULT, 8+4+4+4+4+4*4+4*4); - data << uint64(item->GetGUID()); // item guid - data << uint32(0); // 0, or error code - data << uint32(item->GetPaidMoney()); // money cost - data << uint32(iece->reqhonorpoints); // honor point cost - data << uint32(iece->reqarenapoints); // arena point cost - for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i) // item cost data - { - data << uint32(iece->reqitem[i]); - data << uint32(iece->reqitemcount[i]); - } - GetSession()->SendPacket(&data); + SendItemRefundResult(item, iece, 0); uint32 moneyRefund = item->GetPaidMoney(); // item-> will be invalidated in DestroyItem @@ -26440,10 +27158,10 @@ void Player::RefundItem(Item* item) DestroyItem(item->GetBagSlot(), item->GetSlot(), true); // Grant back extendedcost items - for (uint8 i = 0; i < MAX_ITEM_EXTENDED_COST_REQUIREMENTS; ++i) + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) { - uint32 count = iece->reqitemcount[i]; - uint32 itemid = iece->reqitem[i]; + uint32 count = iece->RequiredItemCount[i]; + uint32 itemid = iece->RequiredItem[i]; if (count && itemid) { ItemPosCountVec dest; @@ -26454,18 +27172,22 @@ void Player::RefundItem(Item* item) } } + // Grant back currencies + for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) + { + if (iece->RequirementFlags & (ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1 << i)) + continue; + + uint32 count = iece->RequiredCurrencyCount[i]; + uint32 currencyid = iece->RequiredCurrency[i]; + if (count && currencyid) + ModifyCurrency(currencyid, count); + } + // Grant back money if (moneyRefund) ModifyMoney(moneyRefund); // Saved in SaveInventoryAndGoldToDB - // Grant back Honor points - if (uint32 honorRefund = iece->reqhonorpoints) - ModifyHonorPoints(honorRefund, trans); - - // Grant back Arena points - if (uint32 arenaRefund = iece->reqarenapoints) - ModifyArenaPoints(arenaRefund, trans); - SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); @@ -26552,89 +27274,119 @@ bool Player::IsInWhisperWhiteList(uint64 guid) return false; } -bool Player::SetDisableGravity(bool disable, bool packetOnly /*= false*/) +uint8 Player::GetNextVoidStorageFreeSlot() const { - if (!packetOnly && !Unit::SetDisableGravity(disable)) - return false; + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + if (!_voidStorageItems[i]) // unused item + return i; - WorldPacket data(disable ? SMSG_MOVE_GRAVITY_DISABLE : SMSG_MOVE_GRAVITY_ENABLE, 12); - data.append(GetPackGUID()); - data << uint32(0); //! movement counter - SendDirectMessage(&data); + return VOID_STORAGE_MAX_SLOT; +} - data.Initialize(MSG_MOVE_GRAVITY_CHNG, 64); - data.append(GetPackGUID()); - BuildMovementPacket(&data); - SendMessageToSet(&data, false); - return true; +uint8 Player::GetNumOfVoidStorageFreeSlots() const +{ + uint8 count = 0; + + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + if (!_voidStorageItems[i]) + count++; + + return count; } -bool Player::SetCanFly(bool apply) +uint8 Player::AddVoidStorageItem(const VoidStorageItem& item) { - if (!Unit::SetCanFly(apply)) - return false; + int8 slot = GetNextVoidStorageFreeSlot(); - WorldPacket data(apply ? SMSG_MOVE_SET_CAN_FLY : SMSG_MOVE_UNSET_CAN_FLY, 12); - data.append(GetPackGUID()); - data << uint32(0); //! movement counter - SendDirectMessage(&data); + if (slot >= VOID_STORAGE_MAX_SLOT) + { + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_FULL); + return 255; + } - data.Initialize(MSG_MOVE_UPDATE_CAN_FLY, 64); - data.append(GetPackGUID()); - BuildMovementPacket(&data); - SendMessageToSet(&data, false); - return true; + _voidStorageItems[slot] = new VoidStorageItem(item.ItemId, item.ItemEntry, + item.CreatorGuid, item.ItemRandomPropertyId, item.ItemSuffixFactor); + return slot; } -bool Player::SetHover(bool apply, bool packetOnly /*= false*/) +void Player::AddVoidStorageItemAtSlot(uint8 slot, const VoidStorageItem& item) { - if (!packetOnly && !Unit::SetHover(apply)) - return false; + if (slot >= VOID_STORAGE_MAX_SLOT) + { + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_FULL); + return; + } - WorldPacket data(apply ? SMSG_MOVE_SET_HOVER : SMSG_MOVE_UNSET_HOVER, 12); - data.append(GetPackGUID()); - data << uint32(0); //! movement counter - SendDirectMessage(&data); + if (_voidStorageItems[slot]) + { + TC_LOG_ERROR("misc", "Player::AddVoidStorageItemAtSlot - Player (GUID: %u, name: %s) tried to add an item to an used slot (item id: " UI64FMTD ", entry: %u, slot: %u).", GetGUIDLow(), GetName().c_str(), _voidStorageItems[slot]->ItemId, _voidStorageItems[slot]->ItemEntry, slot); + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); + return; + } - data.Initialize(MSG_MOVE_HOVER, 64); - data.append(GetPackGUID()); - BuildMovementPacket(&data); - SendMessageToSet(&data, false); - return true; + _voidStorageItems[slot] = new VoidStorageItem(item.ItemId, item.ItemId, + item.CreatorGuid, item.ItemRandomPropertyId, item.ItemSuffixFactor); } -bool Player::SetWaterWalking(bool apply, bool packetOnly /*= false*/) +void Player::DeleteVoidStorageItem(uint8 slot) { - if (!packetOnly && !Unit::SetWaterWalking(apply)) - return false; + if (slot >= VOID_STORAGE_MAX_SLOT) + { + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); + return; + } - WorldPacket data(apply ? SMSG_MOVE_WATER_WALK : SMSG_MOVE_LAND_WALK, 12); - data.append(GetPackGUID()); - data << uint32(0); //! movement counter - SendDirectMessage(&data); + delete _voidStorageItems[slot]; + _voidStorageItems[slot] = NULL; +} - data.Initialize(MSG_MOVE_WATER_WALK, 64); - data.append(GetPackGUID()); - BuildMovementPacket(&data); - SendMessageToSet(&data, false); +bool Player::SwapVoidStorageItem(uint8 oldSlot, uint8 newSlot) +{ + if (oldSlot >= VOID_STORAGE_MAX_SLOT || newSlot >= VOID_STORAGE_MAX_SLOT || oldSlot == newSlot) + return false; + + std::swap(_voidStorageItems[newSlot], _voidStorageItems[oldSlot]); return true; } -bool Player::SetFeatherFall(bool apply, bool packetOnly /*= false*/) +VoidStorageItem* Player::GetVoidStorageItem(uint8 slot) const { - if (!packetOnly && !Unit::SetFeatherFall(apply)) - return false; + if (slot >= VOID_STORAGE_MAX_SLOT) + { + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); + return NULL; + } - WorldPacket data(apply ? SMSG_MOVE_FEATHER_FALL : SMSG_MOVE_NORMAL_FALL, 12); - data.append(GetPackGUID()); - data << uint32(0); //! movement counter - SendDirectMessage(&data); + return _voidStorageItems[slot]; +} - data.Initialize(MSG_MOVE_FEATHER_FALL, 64); - data.append(GetPackGUID()); - BuildMovementPacket(&data); - SendMessageToSet(&data, false); - return true; +VoidStorageItem* Player::GetVoidStorageItem(uint64 id, uint8& slot) const +{ + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + { + if (_voidStorageItems[i] && _voidStorageItems[i]->ItemId == id) + { + slot = i; + return _voidStorageItems[i]; + } + } + + return NULL; +} + +void Player::SendMovementSetCanTransitionBetweenSwimAndFly(bool apply) +{ + Movement::PacketSender(this, NULL_OPCODE, apply ? + SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY : + SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY).Send(); +} + +void Player::SendMovementSetCollisionHeight(float height) +{ + static MovementStatusElements const heightElement = MSEExtraFloat; + Movement::ExtraMovementStatusElement extra(&heightElement); + extra.Data.floatData = height; + Movement::PacketSender(this, NULL_OPCODE, SMSG_MOVE_SET_COLLISION_HEIGHT, SMSG_MOVE_UPDATE_COLLISION_HEIGHT, &extra).Send(); } float Player::GetCollisionHeight(bool mounted) const @@ -26750,6 +27502,9 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy return NULL; } + for (auto itr : GetPhases()) + pet->SetInPhase(itr, false, true); + pet->SetCreatorGUID(GetGUID()); pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction()); @@ -26819,10 +27574,334 @@ bool Player::IsLoading() const return GetSession()->PlayerLoading(); } +bool Player::CanUseMastery() const +{ + return HasSpell(MasterySpells[getClass()]); +} + +void Player::ReadMovementInfo(WorldPacket& data, MovementInfo* mi, Movement::ExtraMovementStatusElement* extras /*= NULL*/) +{ + MovementStatusElements const* sequence = GetMovementStatusElementsSequence(data.GetOpcode()); + if (!sequence) + { + TC_LOG_ERROR("network", "Player::ReadMovementInfo: No movement sequence found for opcode %s", GetOpcodeNameForLogging(data.GetOpcode()).c_str()); + return; + } + + bool hasMovementFlags = false; + bool hasMovementFlags2 = false; + bool hasTimestamp = false; + bool hasOrientation = false; + bool hasTransportData = false; + bool hasTransportTime2 = false; + bool hasTransportTime3 = false; + bool hasPitch = false; + bool hasFallData = false; + bool hasFallDirection = false; + bool hasSplineElevation = false; + + ObjectGuid guid; + ObjectGuid tguid; + + for (; *sequence != MSEEnd; ++sequence) + { + MovementStatusElements const& element = *sequence; + + switch (element) + { + case MSEHasGuidByte0: + case MSEHasGuidByte1: + case MSEHasGuidByte2: + case MSEHasGuidByte3: + case MSEHasGuidByte4: + case MSEHasGuidByte5: + case MSEHasGuidByte6: + case MSEHasGuidByte7: + guid[element - MSEHasGuidByte0] = data.ReadBit(); + break; + case MSEHasTransportGuidByte0: + case MSEHasTransportGuidByte1: + case MSEHasTransportGuidByte2: + case MSEHasTransportGuidByte3: + case MSEHasTransportGuidByte4: + case MSEHasTransportGuidByte5: + case MSEHasTransportGuidByte6: + case MSEHasTransportGuidByte7: + if (hasTransportData) + tguid[element - MSEHasTransportGuidByte0] = data.ReadBit(); + break; + case MSEGuidByte0: + case MSEGuidByte1: + case MSEGuidByte2: + case MSEGuidByte3: + case MSEGuidByte4: + case MSEGuidByte5: + case MSEGuidByte6: + case MSEGuidByte7: + data.ReadByteSeq(guid[element - MSEGuidByte0]); + break; + case MSETransportGuidByte0: + case MSETransportGuidByte1: + case MSETransportGuidByte2: + case MSETransportGuidByte3: + case MSETransportGuidByte4: + case MSETransportGuidByte5: + case MSETransportGuidByte6: + case MSETransportGuidByte7: + if (hasTransportData) + data.ReadByteSeq(tguid[element - MSETransportGuidByte0]); + break; + case MSEHasMovementFlags: + hasMovementFlags = !data.ReadBit(); + break; + case MSEHasMovementFlags2: + hasMovementFlags2 = !data.ReadBit(); + break; + case MSEHasTimestamp: + hasTimestamp = !data.ReadBit(); + break; + case MSEHasOrientation: + hasOrientation = !data.ReadBit(); + break; + case MSEHasTransportData: + hasTransportData = data.ReadBit(); + break; + case MSEHasTransportTime2: + if (hasTransportData) + hasTransportTime2 = data.ReadBit(); + break; + case MSEHasTransportTime3: + if (hasTransportData) + hasTransportTime3 = data.ReadBit(); + break; + case MSEHasPitch: + hasPitch = !data.ReadBit(); + break; + case MSEHasFallData: + hasFallData = data.ReadBit(); + break; + case MSEHasFallDirection: + if (hasFallData) + hasFallDirection = data.ReadBit(); + break; + case MSEHasSplineElevation: + hasSplineElevation = !data.ReadBit(); + break; + case MSEHasSpline: + data.ReadBit(); + break; + case MSEMovementFlags: + if (hasMovementFlags) + mi->flags = data.ReadBits(30); + break; + case MSEMovementFlags2: + if (hasMovementFlags2) + mi->flags2 = data.ReadBits(12); + break; + case MSETimestamp: + if (hasTimestamp) + data >> mi->time; + break; + case MSEPositionX: + data >> mi->pos.m_positionX; + break; + case MSEPositionY: + data >> mi->pos.m_positionY; + break; + case MSEPositionZ: + data >> mi->pos.m_positionZ; + break; + case MSEOrientation: + if (hasOrientation) + mi->pos.SetOrientation(data.read<float>()); + break; + case MSETransportPositionX: + if (hasTransportData) + data >> mi->transport.pos.m_positionX; + break; + case MSETransportPositionY: + if (hasTransportData) + data >> mi->transport.pos.m_positionY; + break; + case MSETransportPositionZ: + if (hasTransportData) + data >> mi->transport.pos.m_positionZ; + break; + case MSETransportOrientation: + if (hasTransportData) + mi->transport.pos.SetOrientation(data.read<float>()); + break; + case MSETransportSeat: + if (hasTransportData) + data >> mi->transport.seat; + break; + case MSETransportTime: + if (hasTransportData) + data >> mi->transport.time; + break; + case MSETransportTime2: + if (hasTransportData && hasTransportTime2) + data >> mi->transport.time2; + break; + case MSETransportTime3: + if (hasTransportData && hasTransportTime3) + data >> mi->transport.time3; + break; + case MSEPitch: + if (hasPitch) + mi->pitch = G3D::wrap(data.read<float>(), float(-M_PI), float(M_PI)); + break; + case MSEFallTime: + if (hasFallData) + data >> mi->jump.fallTime; + break; + case MSEFallVerticalSpeed: + if (hasFallData) + data >> mi->jump.zspeed; + break; + case MSEFallCosAngle: + if (hasFallData && hasFallDirection) + data >> mi->jump.cosAngle; + break; + case MSEFallSinAngle: + if (hasFallData && hasFallDirection) + data >> mi->jump.sinAngle; + break; + case MSEFallHorizontalSpeed: + if (hasFallData && hasFallDirection) + data >> mi->jump.xyspeed; + break; + case MSESplineElevation: + if (hasSplineElevation) + data >> mi->splineElevation; + break; + case MSECounter: + data.read_skip<uint32>(); /// @TODO: Maybe compare it with m_movementCounter to verify that packets are sent & received in order? + break; + case MSEZeroBit: + case MSEOneBit: + data.ReadBit(); + break; + case MSEExtraElement: + extras->ReadNextElement(data); + break; + default: + ASSERT(Movement::PrintInvalidSequenceElement(element, __FUNCTION__)); + break; + } + } + + mi->guid = guid; + mi->transport.guid = tguid; + + //! Anti-cheat checks. Please keep them in seperate if () blocks to maintain a clear overview. + //! Might be subject to latency, so just remove improper flags. + #ifdef TRINITY_DEBUG + #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \ + { \ + if (check) \ + { \ + TC_LOG_DEBUG("entities.unit", "Player::ReadMovementInfo: Violation of MovementFlags found (%s). " \ + "MovementFlags: %u, MovementFlags2: %u for player GUID: %u. Mask %u will be removed.", \ + STRINGIZE(check), mi->GetMovementFlags(), mi->GetExtraMovementFlags(), GetGUIDLow(), maskToRemove); \ + mi->RemoveMovementFlag((maskToRemove)); \ + } \ + } + #else + #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \ + if (check) \ + mi->RemoveMovementFlag((maskToRemove)); + #endif + + /*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid + in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD. + It will freeze clients that receive this player's movement info. + */ + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT), + MOVEMENTFLAG_ROOT); + + //! Cannot hover without SPELL_AURA_HOVER + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !HasAuraType(SPELL_AURA_HOVER), + MOVEMENTFLAG_HOVER); + + //! Cannot ascend and descend at the same time + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ASCENDING) && mi->HasMovementFlag(MOVEMENTFLAG_DESCENDING), + MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING); + + //! Cannot move left and right at the same time + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_RIGHT), + MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT); + + //! Cannot strafe left and right at the same time + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_RIGHT), + MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT); + + //! Cannot pitch up and down at the same time + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_PITCH_UP) && mi->HasMovementFlag(MOVEMENTFLAG_PITCH_DOWN), + MOVEMENTFLAG_PITCH_UP | MOVEMENTFLAG_PITCH_DOWN); + + //! Cannot move forwards and backwards at the same time + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FORWARD) && mi->HasMovementFlag(MOVEMENTFLAG_BACKWARD), + MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD); + + //! Cannot walk on water without SPELL_AURA_WATER_WALK + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_WATERWALKING) && !HasAuraType(SPELL_AURA_WATER_WALK), + MOVEMENTFLAG_WATERWALKING); + + //! Cannot feather fall without SPELL_AURA_FEATHER_FALL + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FALLING_SLOW) && !HasAuraType(SPELL_AURA_FEATHER_FALL), + MOVEMENTFLAG_FALLING_SLOW); + + /*! Cannot fly if no fly auras present. Exception is being a GM. + Note that we check for account level instead of Player::IsGameMaster() because in some + situations it may be feasable to use .gm fly on as a GM without having .gm on, + e.g. aerial combat. + */ + + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && ToPlayer()->GetSession()->GetSecurity() == SEC_PLAYER && + !ToPlayer()->m_mover->HasAuraType(SPELL_AURA_FLY) && + !ToPlayer()->m_mover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED), + MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY); + + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY | MOVEMENTFLAG_CAN_FLY) && mi->HasMovementFlag(MOVEMENTFLAG_FALLING), + MOVEMENTFLAG_FALLING); + + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FALLING) && (!hasFallData || !hasFallDirection), MOVEMENTFLAG_FALLING); + + REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION) && + (!hasSplineElevation || G3D::fuzzyEq(mi->splineElevation, 0.0f)), MOVEMENTFLAG_SPLINE_ELEVATION); + + // Client first checks if spline elevation != 0, then verifies flag presence + if (hasSplineElevation) + mi->AddMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION); + + #undef REMOVE_VIOLATING_FLAGS +} + +void Player::UpdatePhasing() +{ + if (!IsInWorld()) + return; + + std::set<uint32> phaseIds; + std::set<uint32> terrainswaps; + std::set<uint32> worldAreaSwaps; + + for (auto phase : GetPhases()) + { + PhaseInfo const* info = sObjectMgr->GetPhaseInfo(phase); + if (!info) + continue; + terrainswaps.insert(info->terrainSwapMap); + worldAreaSwaps.insert(info->worldMapAreaSwap); + } + + GetSession()->SendSetPhaseShift(GetPhases(), terrainswaps, worldAreaSwaps); +} + void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) { WorldPacket data(SMSG_SUPERCEDED_SPELL, 8); - data << uint32(oldSpell) << uint32(newSpell); + data << uint32(newSpell) << uint32(oldSpell); GetSession()->SendPacket(&data); } - diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 851afecdbaf..ef65558e13c 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -28,6 +28,8 @@ #include "QuestDef.h" #include "SpellMgr.h" #include "Unit.h" +#include "Opcodes.h" +#include "WorldSession.h" #include <limits> #include <string> @@ -35,10 +37,11 @@ struct CreatureTemplate; struct Mail; +struct ItemExtendedCostEntry; struct TrainerSpell; struct VendorItem; -class AchievementMgr; +template<class T> class AchievementMgr; class ReputationMgr; class Channel; class CharacterCreateInfo; @@ -55,9 +58,9 @@ class UpdateMask; typedef std::deque<Mail*> PlayerMails; -#define PLAYER_MAX_SKILLS 127 +#define PLAYER_MAX_SKILLS 128 #define PLAYER_MAX_DAILY_QUESTS 25 -#define PLAYER_EXPLORED_ZONES_SIZE 128 +#define PLAYER_EXPLORED_ZONES_SIZE 156 // Note: SPELLMOD_* values is aura types in fact enum SpellModType @@ -109,6 +112,42 @@ struct PlayerTalent uint8 spec : 8; }; +extern uint32 const MasterySpells[MAX_CLASSES]; + +enum TalentTree // talent tabs +{ + TALENT_TREE_WARRIOR_ARMS = 746, + TALENT_TREE_WARRIOR_FURY = 815, + TALENT_TREE_WARRIOR_PROTECTION = 845, + TALENT_TREE_PALADIN_HOLY = 831, + TALENT_TREE_PALADIN_PROTECTION = 839, + TALENT_TREE_PALADIN_RETRIBUTION = 855, + TALENT_TREE_HUNTER_BEAST_MASTERY = 811, + TALENT_TREE_HUNTER_MARKSMANSHIP = 807, + TALENT_TREE_HUNTER_SURVIVAL = 809, + TALENT_TREE_ROGUE_ASSASSINATION = 182, + TALENT_TREE_ROGUE_COMBAT = 181, + TALENT_TREE_ROGUE_SUBTLETY = 183, + TALENT_TREE_PRIEST_DISCIPLINE = 760, + TALENT_TREE_PRIEST_HOLY = 813, + TALENT_TREE_PRIEST_SHADOW = 795, + TALENT_TREE_DEATH_KNIGHT_BLOOD = 398, + TALENT_TREE_DEATH_KNIGHT_FROST = 399, + TALENT_TREE_DEATH_KNIGHT_UNHOLY = 400, + TALENT_TREE_SHAMAN_ELEMENTAL = 261, + TALENT_TREE_SHAMAN_ENHANCEMENT = 263, + TALENT_TREE_SHAMAN_RESTORATION = 262, + TALENT_TREE_MAGE_ARCANE = 799, + TALENT_TREE_MAGE_FIRE = 851, + TALENT_TREE_MAGE_FROST = 823, + TALENT_TREE_WARLOCK_AFFLICTION = 871, + TALENT_TREE_WARLOCK_DEMONOLOGY = 867, + TALENT_TREE_WARLOCK_DESTRUCTION = 865, + TALENT_TREE_DRUID_BALANCE = 752, + TALENT_TREE_DRUID_FERAL_COMBAT = 750, + TALENT_TREE_DRUID_RESTORATION = 748 +}; + // Spell modifier (used for modify other spells) struct SpellModifier { @@ -122,12 +161,121 @@ struct SpellModifier Aura* const ownerAura; }; +enum PlayerCurrencyState +{ + PLAYERCURRENCY_UNCHANGED = 0, + PLAYERCURRENCY_CHANGED = 1, + PLAYERCURRENCY_NEW = 2, + PLAYERCURRENCY_REMOVED = 3 //not removed just set count == 0 +}; + +struct PlayerCurrency +{ + PlayerCurrencyState state; + uint32 totalCount; + uint32 weekCount; +}; + typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap; typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap; typedef std::list<SpellModifier*> SpellModList; +typedef std::unordered_map<uint32, PlayerCurrency> PlayerCurrenciesMap; typedef std::list<uint64> WhisperListContainer; +/// Maximum number of CompactUnitFrames profiles +#define MAX_CUF_PROFILES 5 + +/// Bit index used in the many bool options of CompactUnitFrames +enum CUFBoolOptions +{ + CUF_KEEP_GROUPS_TOGETHER, + CUF_DISPLAY_PETS, + CUF_DISPLAY_MAIN_TANK_AND_ASSIST, + CUF_DISPLAY_HEAL_PREDICTION, + CUF_DISPLAY_AGGRO_HIGHLIGHT, + CUF_DISPLAY_ONLY_DISPELLABLE_DEBUFFS, + CUF_DISPLAY_POWER_BAR, + CUF_DISPLAY_BORDER, + CUF_USE_CLASS_COLORS, + CUF_DISPLAY_NON_BOSS_DEBUFFS, + CUF_DISPLAY_HORIZONTAL_GROUPS, + CUF_LOCKED, + CUF_SHOWN, + CUF_AUTO_ACTIVATE_2_PLAYERS, + CUF_AUTO_ACTIVATE_3_PLAYERS, + CUF_AUTO_ACTIVATE_5_PLAYERS, + CUF_AUTO_ACTIVATE_10_PLAYERS, + CUF_AUTO_ACTIVATE_15_PLAYERS, + CUF_AUTO_ACTIVATE_25_PLAYERS, + CUF_AUTO_ACTIVATE_40_PLAYERS, + CUF_AUTO_ACTIVATE_SPEC_1, + CUF_AUTO_ACTIVATE_SPEC_2, + CUF_AUTO_ACTIVATE_PVP, + CUF_AUTO_ACTIVATE_PVE, + CUF_UNK_145, + CUF_UNK_156, + CUF_UNK_157, + + // The unks is _LOCKED and _SHOWN and _DYNAMIC, unknown order + + CUF_BOOL_OPTIONS_COUNT, +}; + +/// Represents a CompactUnitFrame profile +struct CUFProfile +{ + CUFProfile() : ProfileName(), BoolOptions() // might want to change default value for options + { + FrameHeight = 0; + FrameWidth = 0; + SortBy = 0; + HealthText = 0; + Unk146 = 0; + Unk147 = 0; + Unk148 = 0; + Unk150 = 0; + Unk152 = 0; + Unk154 = 0; + } + + CUFProfile(const std::string& name, uint16 frameHeight, uint16 frameWidth, uint8 sortBy, uint8 healthText, uint32 boolOptions, + uint8 unk146, uint8 unk147, uint8 unk148, uint16 unk150, uint16 unk152, uint16 unk154) + : ProfileName(name), BoolOptions((int)boolOptions) + { + FrameHeight = frameHeight; + FrameWidth = frameWidth; + SortBy = sortBy; + HealthText = healthText; + Unk146 = unk146; + Unk147 = unk147; + Unk148 = unk148; + Unk150 = unk150; + Unk152 = unk152; + Unk154 = unk154; + } + + std::string ProfileName; + uint16 FrameHeight; + uint16 FrameWidth; + uint8 SortBy; + uint8 HealthText; + + // LeftAlign, TopAlight, BottomAllign (unk order) + uint8 Unk146; + uint8 Unk147; + uint8 Unk148; + + // LeftOffset, TopOffset and BottomOffset (unk order) + uint16 Unk150; + uint16 Unk152; + uint16 Unk154; + + std::bitset<CUF_BOOL_OPTIONS_COUNT> BoolOptions; + + // More fields can be added to BoolOptions without changing DB schema (up to 32, currently 27) +}; + struct SpellCooldown { time_t end; @@ -139,9 +287,9 @@ typedef std::unordered_map<uint32 /*instanceId*/, time_t/*releaseTime*/> Instanc enum TrainerSpellState { - TRAINER_SPELL_GREEN = 0, - TRAINER_SPELL_RED = 1, - TRAINER_SPELL_GRAY = 2, + TRAINER_SPELL_GRAY = 0, + TRAINER_SPELL_GREEN = 1, + TRAINER_SPELL_RED = 2, TRAINER_SPELL_GREEN_DISABLED = 10 // custom value, not send to client: formally green but learn not allowed }; @@ -158,6 +306,7 @@ enum ActionButtonType ACTION_BUTTON_SPELL = 0x00, ACTION_BUTTON_C = 0x01, // click? ACTION_BUTTON_EQSET = 0x20, + ACTION_BUTTON_DROPDOWN = 0x30, ACTION_BUTTON_MACRO = 0x40, ACTION_BUTTON_CMACRO = ACTION_BUTTON_C | ACTION_BUTTON_MACRO, ACTION_BUTTON_ITEM = 0x80 @@ -214,20 +363,6 @@ struct PlayerCreateInfoItem typedef std::list<PlayerCreateInfoItem> PlayerCreateInfoItems; -struct PlayerClassLevelInfo -{ - PlayerClassLevelInfo() : basehealth(0), basemana(0) { } - uint16 basehealth; - uint16 basemana; -}; - -struct PlayerClassInfo -{ - PlayerClassInfo() : levelInfo(NULL) { } - - PlayerClassLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1 -}; - struct PlayerLevelInfo { PlayerLevelInfo() { for (uint8 i=0; i < MAX_STATS; ++i) stats[i] = 0; } @@ -272,6 +407,7 @@ struct PlayerInfo uint16 displayId_f; PlayerCreateInfoItems item; PlayerCreateInfoSpells customSpells; + PlayerCreateInfoSpells castSpells; PlayerCreateInfoActions action; PlayerCreateInfoSkills skills; @@ -365,14 +501,6 @@ struct EnchantDuration typedef std::list<EnchantDuration> EnchantDurationList; typedef std::list<Item*> ItemDurationList; -enum PlayerMovementType -{ - MOVE_ROOT = 1, - MOVE_UNROOT = 2, - MOVE_WATER_WALK = 3, - MOVE_LAND_WALK = 4 -}; - enum DrunkenState { DRUNKEN_SOBER = 0, @@ -385,87 +513,42 @@ enum DrunkenState enum PlayerFlags { - PLAYER_FLAGS_GROUP_LEADER = 0x00000001, - PLAYER_FLAGS_AFK = 0x00000002, - PLAYER_FLAGS_DND = 0x00000004, - PLAYER_FLAGS_GM = 0x00000008, - PLAYER_FLAGS_GHOST = 0x00000010, - PLAYER_FLAGS_RESTING = 0x00000020, - PLAYER_FLAGS_UNK6 = 0x00000040, - PLAYER_FLAGS_UNK7 = 0x00000080, // pre-3.0.3 PLAYER_FLAGS_FFA_PVP flag for FFA PVP state - PLAYER_FLAGS_CONTESTED_PVP = 0x00000100, // Player has been involved in a PvP combat and will be attacked by contested guards - PLAYER_FLAGS_IN_PVP = 0x00000200, - PLAYER_FLAGS_HIDE_HELM = 0x00000400, - PLAYER_FLAGS_HIDE_CLOAK = 0x00000800, - PLAYER_FLAGS_PLAYED_LONG_TIME = 0x00001000, // played long time - PLAYER_FLAGS_PLAYED_TOO_LONG = 0x00002000, // played too long time - PLAYER_FLAGS_IS_OUT_OF_BOUNDS = 0x00004000, - PLAYER_FLAGS_DEVELOPER = 0x00008000, // <Dev> prefix for something? - PLAYER_FLAGS_UNK16 = 0x00010000, // pre-3.0.3 PLAYER_FLAGS_SANCTUARY flag for player entered sanctuary - PLAYER_FLAGS_TAXI_BENCHMARK = 0x00020000, // taxi benchmark mode (on/off) (2.0.1) - PLAYER_FLAGS_PVP_TIMER = 0x00040000, // 3.0.2, pvp timer active (after you disable pvp manually) - PLAYER_FLAGS_UBER = 0x00080000, - PLAYER_FLAGS_UNK20 = 0x00100000, - PLAYER_FLAGS_UNK21 = 0x00200000, - PLAYER_FLAGS_COMMENTATOR2 = 0x00400000, - PLAYER_ALLOW_ONLY_ABILITY = 0x00800000, // used by bladestorm and killing spree, allowed only spells with SPELL_ATTR0_REQ_AMMO, SPELL_EFFECT_ATTACK, checked only for active player - PLAYER_FLAGS_UNK24 = 0x01000000, // disabled all melee ability on tab include autoattack - PLAYER_FLAGS_NO_XP_GAIN = 0x02000000, - PLAYER_FLAGS_UNK26 = 0x04000000, - PLAYER_FLAGS_UNK27 = 0x08000000, - PLAYER_FLAGS_UNK28 = 0x10000000, - PLAYER_FLAGS_UNK29 = 0x20000000, - PLAYER_FLAGS_UNK30 = 0x40000000, - PLAYER_FLAGS_UNK31 = 0x80000000 -}; - -// used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1<<bit_index) without (-1) -// can't use enum for uint64 values -#define PLAYER_TITLE_DISABLED UI64LIT(0x0000000000000000) -#define PLAYER_TITLE_NONE UI64LIT(0x0000000000000001) -#define PLAYER_TITLE_PRIVATE UI64LIT(0x0000000000000002) // 1 -#define PLAYER_TITLE_CORPORAL UI64LIT(0x0000000000000004) // 2 -#define PLAYER_TITLE_SERGEANT_A UI64LIT(0x0000000000000008) // 3 -#define PLAYER_TITLE_MASTER_SERGEANT UI64LIT(0x0000000000000010) // 4 -#define PLAYER_TITLE_SERGEANT_MAJOR UI64LIT(0x0000000000000020) // 5 -#define PLAYER_TITLE_KNIGHT UI64LIT(0x0000000000000040) // 6 -#define PLAYER_TITLE_KNIGHT_LIEUTENANT UI64LIT(0x0000000000000080) // 7 -#define PLAYER_TITLE_KNIGHT_CAPTAIN UI64LIT(0x0000000000000100) // 8 -#define PLAYER_TITLE_KNIGHT_CHAMPION UI64LIT(0x0000000000000200) // 9 -#define PLAYER_TITLE_LIEUTENANT_COMMANDER UI64LIT(0x0000000000000400) // 10 -#define PLAYER_TITLE_COMMANDER UI64LIT(0x0000000000000800) // 11 -#define PLAYER_TITLE_MARSHAL UI64LIT(0x0000000000001000) // 12 -#define PLAYER_TITLE_FIELD_MARSHAL UI64LIT(0x0000000000002000) // 13 -#define PLAYER_TITLE_GRAND_MARSHAL UI64LIT(0x0000000000004000) // 14 -#define PLAYER_TITLE_SCOUT UI64LIT(0x0000000000008000) // 15 -#define PLAYER_TITLE_GRUNT UI64LIT(0x0000000000010000) // 16 -#define PLAYER_TITLE_SERGEANT_H UI64LIT(0x0000000000020000) // 17 -#define PLAYER_TITLE_SENIOR_SERGEANT UI64LIT(0x0000000000040000) // 18 -#define PLAYER_TITLE_FIRST_SERGEANT UI64LIT(0x0000000000080000) // 19 -#define PLAYER_TITLE_STONE_GUARD UI64LIT(0x0000000000100000) // 20 -#define PLAYER_TITLE_BLOOD_GUARD UI64LIT(0x0000000000200000) // 21 -#define PLAYER_TITLE_LEGIONNAIRE UI64LIT(0x0000000000400000) // 22 -#define PLAYER_TITLE_CENTURION UI64LIT(0x0000000000800000) // 23 -#define PLAYER_TITLE_CHAMPION UI64LIT(0x0000000001000000) // 24 -#define PLAYER_TITLE_LIEUTENANT_GENERAL UI64LIT(0x0000000002000000) // 25 -#define PLAYER_TITLE_GENERAL UI64LIT(0x0000000004000000) // 26 -#define PLAYER_TITLE_WARLORD UI64LIT(0x0000000008000000) // 27 -#define PLAYER_TITLE_HIGH_WARLORD UI64LIT(0x0000000010000000) // 28 -#define PLAYER_TITLE_GLADIATOR UI64LIT(0x0000000020000000) // 29 -#define PLAYER_TITLE_DUELIST UI64LIT(0x0000000040000000) // 30 -#define PLAYER_TITLE_RIVAL UI64LIT(0x0000000080000000) // 31 -#define PLAYER_TITLE_CHALLENGER UI64LIT(0x0000000100000000) // 32 -#define PLAYER_TITLE_SCARAB_LORD UI64LIT(0x0000000200000000) // 33 -#define PLAYER_TITLE_CONQUEROR UI64LIT(0x0000000400000000) // 34 -#define PLAYER_TITLE_JUSTICAR UI64LIT(0x0000000800000000) // 35 -#define PLAYER_TITLE_CHAMPION_OF_THE_NAARU UI64LIT(0x0000001000000000) // 36 -#define PLAYER_TITLE_MERCILESS_GLADIATOR UI64LIT(0x0000002000000000) // 37 -#define PLAYER_TITLE_OF_THE_SHATTERED_SUN UI64LIT(0x0000004000000000) // 38 -#define PLAYER_TITLE_HAND_OF_ADAL UI64LIT(0x0000008000000000) // 39 -#define PLAYER_TITLE_VENGEFUL_GLADIATOR UI64LIT(0x0000010000000000) // 40 - -#define KNOWN_TITLES_SIZE 3 -#define MAX_TITLE_INDEX (KNOWN_TITLES_SIZE*64) // 3 uint64 fields + PLAYER_FLAGS_GROUP_LEADER = 0x00000001, + PLAYER_FLAGS_AFK = 0x00000002, + PLAYER_FLAGS_DND = 0x00000004, + PLAYER_FLAGS_GM = 0x00000008, + PLAYER_FLAGS_GHOST = 0x00000010, + PLAYER_FLAGS_RESTING = 0x00000020, + PLAYER_FLAGS_UNK6 = 0x00000040, + PLAYER_FLAGS_UNK7 = 0x00000080, // pre-3.0.3 PLAYER_FLAGS_FFA_PVP flag for FFA PVP state + PLAYER_FLAGS_CONTESTED_PVP = 0x00000100, // Player has been involved in a PvP combat and will be attacked by contested guards + PLAYER_FLAGS_IN_PVP = 0x00000200, + PLAYER_FLAGS_HIDE_HELM = 0x00000400, + PLAYER_FLAGS_HIDE_CLOAK = 0x00000800, + PLAYER_FLAGS_PLAYED_LONG_TIME = 0x00001000, // played long time + PLAYER_FLAGS_PLAYED_TOO_LONG = 0x00002000, // played too long time + PLAYER_FLAGS_IS_OUT_OF_BOUNDS = 0x00004000, + PLAYER_FLAGS_DEVELOPER = 0x00008000, // <Dev> prefix for something? + PLAYER_FLAGS_UNK16 = 0x00010000, // pre-3.0.3 PLAYER_FLAGS_SANCTUARY flag for player entered sanctuary + PLAYER_FLAGS_TAXI_BENCHMARK = 0x00020000, // taxi benchmark mode (on/off) (2.0.1) + PLAYER_FLAGS_PVP_TIMER = 0x00040000, // 3.0.2, pvp timer active (after you disable pvp manually) + PLAYER_FLAGS_UBER = 0x00080000, + PLAYER_FLAGS_UNK20 = 0x00100000, + PLAYER_FLAGS_UNK21 = 0x00200000, + PLAYER_FLAGS_COMMENTATOR2 = 0x00400000, + PLAYER_ALLOW_ONLY_ABILITY = 0x00800000, // used by bladestorm and killing spree, allowed only spells with SPELL_ATTR0_REQ_AMMO, SPELL_EFFECT_ATTACK, checked only for active player + PLAYER_FLAGS_UNK24 = 0x01000000, // disabled all melee ability on tab include autoattack + PLAYER_FLAGS_NO_XP_GAIN = 0x02000000, + PLAYER_FLAGS_UNK26 = 0x04000000, + PLAYER_FLAGS_AUTO_DECLINE_GUILD = 0x08000000, // Automatically declines guild invites + PLAYER_FLAGS_GUILD_LEVEL_ENABLED = 0x10000000, // Lua_GetGuildLevelEnabled() - enables guild leveling related UI + PLAYER_FLAGS_VOID_UNLOCKED = 0x20000000, // void storage + PLAYER_FLAGS_UNK30 = 0x40000000, + PLAYER_FLAGS_UNK31 = 0x80000000 +}; + +#define KNOWN_TITLES_SIZE 4 +#define MAX_TITLE_INDEX (KNOWN_TITLES_SIZE * 64) // 4 uint64 fields // used in PLAYER_FIELD_BYTES values enum PlayerFieldByteFlags @@ -487,7 +570,7 @@ enum MirrorTimerType { FATIGUE_TIMER = 0, BREATH_TIMER = 1, - FIRE_TIMER = 2 + FIRE_TIMER = 2 // feign death }; #define MAX_TIMERS 3 #define DISABLED_MIRROR_TIMER -1 @@ -501,7 +584,6 @@ enum PlayerExtraFlags PLAYER_EXTRA_TAXICHEAT = 0x0008, PLAYER_EXTRA_GM_INVISIBLE = 0x0010, PLAYER_EXTRA_GM_CHAT = 0x0020, // Show GM badge in chat messages - PLAYER_EXTRA_HAS_310_FLYER = 0x0040, // Marks if player already has 310% speed flying mount // other states PLAYER_EXTRA_PVP_DEATH = 0x0100 // store PvP death status until corpse creating. @@ -573,7 +655,7 @@ enum PlayerSlots // first slot for item stored (in any way in player m_items data) PLAYER_SLOT_START = 0, // last+1 slot for item stored (in any way in player m_items data) - PLAYER_SLOT_END = 150, + PLAYER_SLOT_END = 86, PLAYER_SLOTS_COUNT = (PLAYER_SLOT_END - PLAYER_SLOT_START) }; @@ -635,18 +717,6 @@ enum BuyBackSlots // 12 slots BUYBACK_SLOT_END = 86 }; -enum KeyRingSlots // 32 slots -{ - KEYRING_SLOT_START = 86, - KEYRING_SLOT_END = 118 -}; - -enum CurrencyTokenSlots // 32 slots -{ - CURRENCYTOKEN_SLOT_START = 118, - CURRENCYTOKEN_SLOT_END = 150 -}; - enum EquipmentSetUpdateState { EQUIPMENT_SET_UNCHANGED = 0, @@ -694,22 +764,24 @@ enum TradeSlots enum TransferAbortReason { - TRANSFER_ABORT_NONE = 0x00, - TRANSFER_ABORT_ERROR = 0x01, - TRANSFER_ABORT_MAX_PLAYERS = 0x02, // Transfer Aborted: instance is full - TRANSFER_ABORT_NOT_FOUND = 0x03, // Transfer Aborted: instance not found - TRANSFER_ABORT_TOO_MANY_INSTANCES = 0x04, // You have entered too many instances recently. - TRANSFER_ABORT_ZONE_IN_COMBAT = 0x06, // Unable to zone in while an encounter is in progress. - TRANSFER_ABORT_INSUF_EXPAN_LVL = 0x07, // You must have <TBC, WotLK> expansion installed to access this area. - TRANSFER_ABORT_DIFFICULTY = 0x08, // <Normal, Heroic, Epic> difficulty mode is not available for %s. - TRANSFER_ABORT_UNIQUE_MESSAGE = 0x09, // Until you've escaped TLK's grasp, you cannot leave this place! - TRANSFER_ABORT_TOO_MANY_REALM_INSTANCES = 0x0A, // Additional instances cannot be launched, please try again later. - TRANSFER_ABORT_NEED_GROUP = 0x0B, // 3.1 - TRANSFER_ABORT_NOT_FOUND1 = 0x0C, // 3.1 - TRANSFER_ABORT_NOT_FOUND2 = 0x0D, // 3.1 - TRANSFER_ABORT_NOT_FOUND3 = 0x0E, // 3.2 - TRANSFER_ABORT_REALM_ONLY = 0x0F, // All players on party must be from the same realm. - TRANSFER_ABORT_MAP_NOT_ALLOWED = 0x10 // Map can't be entered at this time. + TRANSFER_ABORT_NONE = 0x00, + TRANSFER_ABORT_ERROR = 0x01, + TRANSFER_ABORT_MAX_PLAYERS = 0x02, // Transfer Aborted: instance is full + TRANSFER_ABORT_NOT_FOUND = 0x03, // Transfer Aborted: instance not found + TRANSFER_ABORT_TOO_MANY_INSTANCES = 0x04, // You have entered too many instances recently. + TRANSFER_ABORT_ZONE_IN_COMBAT = 0x06, // Unable to zone in while an encounter is in progress. + TRANSFER_ABORT_INSUF_EXPAN_LVL = 0x07, // You must have <TBC, WotLK> expansion installed to access this area. + TRANSFER_ABORT_DIFFICULTY = 0x08, // <Normal, Heroic, Epic> difficulty mode is not available for %s. + TRANSFER_ABORT_UNIQUE_MESSAGE = 0x09, // Until you've escaped TLK's grasp, you cannot leave this place! + TRANSFER_ABORT_TOO_MANY_REALM_INSTANCES = 0x0A, // Additional instances cannot be launched, please try again later. + TRANSFER_ABORT_NEED_GROUP = 0x0B, // 3.1 + TRANSFER_ABORT_NOT_FOUND1 = 0x0C, // 3.1 + TRANSFER_ABORT_NOT_FOUND2 = 0x0D, // 3.1 + TRANSFER_ABORT_NOT_FOUND3 = 0x0E, // 3.2 + TRANSFER_ABORT_REALM_ONLY = 0x0F, // All players on party must be from the same realm. + TRANSFER_ABORT_MAP_NOT_ALLOWED = 0x10, // Map can't be entered at this time. + TRANSFER_ABORT_LOCKED_TO_DIFFERENT_INSTANCE = 0x12, // 4.2.2 + TRANSFER_ABORT_ALREADY_COMPLETED_ENCOUNTER = 0x13 // 4.2.2 }; enum InstanceResetWarningType @@ -772,7 +844,9 @@ enum PlayerChatTag CHAT_TAG_DND = 0x02, CHAT_TAG_GM = 0x04, CHAT_TAG_COM = 0x08, // Commentator - CHAT_TAG_DEV = 0x10 + CHAT_TAG_DEV = 0x10, + CHAT_TAG_BOSS_SOUND = 0x20, // Plays "RaidBossEmoteWarning" sound on raid boss emote/whisper + CHAT_TAG_MOBILE = 0x40 }; enum PlayedTimeIndex @@ -819,6 +893,9 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES = 30, PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS = 31, PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32, + PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE = 33, + PLAYER_LOGIN_QUERY_LOAD_CURRENCY = 34, + PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES = 35, MAX_PLAYER_LOGIN_QUERY }; @@ -836,7 +913,7 @@ enum PlayerDelayedOperations // Player summoning auto-decline time (in secs) #define MAX_PLAYER_SUMMON_DELAY (2*MINUTE) // Maximum money amount : 2^31 - 1 -extern uint32 const MAX_MONEY_AMOUNT; +extern uint64 const MAX_MONEY_AMOUNT; struct InstancePlayerBind { @@ -852,7 +929,6 @@ struct AccessRequirement { uint8 levelMin; uint8 levelMax; - uint16 item_level; uint32 item; uint32 item2; uint32 quest_A; @@ -868,12 +944,6 @@ enum CharDeleteMethod // the name gets freed up and appears as deleted ingame }; -enum CurrencyItems -{ - ITEM_HONOR_POINTS_ID = 43308, - ITEM_ARENA_POINTS_ID = 43307 -}; - enum ReferAFriendError { ERR_REFER_A_FRIEND_NONE = 0x00, @@ -920,14 +990,14 @@ class PlayerTaxi bool IsTaximaskNodeKnown(uint32 nodeidx) const { - uint8 field = uint8((nodeidx - 1) / 32); - uint32 submask = 1 << ((nodeidx-1) % 32); + uint8 field = uint8((nodeidx - 1) / 8); + uint32 submask = 1 << ((nodeidx-1) % 8); return (m_taximask[field] & submask) == submask; } bool SetTaximaskNode(uint32 nodeidx) { - uint8 field = uint8((nodeidx - 1) / 32); - uint32 submask = 1 << ((nodeidx - 1) % 32); + uint8 field = uint8((nodeidx - 1) / 8); + uint32 submask = 1 << ((nodeidx- 1) % 8); if ((m_taximask[field] & submask) != submask) { m_taximask[field] |= submask; @@ -968,12 +1038,14 @@ class Player; struct BGData { BGData() : bgInstanceID(0), bgTypeID(BATTLEGROUND_TYPE_NONE), bgAfkReportedCount(0), bgAfkReportedTimer(0), - bgTeam(0), mountSpell(0) { ClearTaxiPath(); } + bgTeam(0), mountSpell(0) { bgQueuesJoinedTime.clear(); ClearTaxiPath(); } uint32 bgInstanceID; ///< This variable is set to bg->m_InstanceID, /// when player is teleported to BG - (it is battleground's GUID) BattlegroundTypeId bgTypeID; + std::map<uint32, uint32> bgQueuesJoinedTime; + std::set<uint32> bgAfkReporter; uint8 bgAfkReportedCount; time_t bgAfkReportedTimer; @@ -989,6 +1061,33 @@ struct BGData bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; } }; +struct VoidStorageItem +{ + VoidStorageItem() + { + ItemId = 0; + ItemEntry = 0; + CreatorGuid = 0; + ItemRandomPropertyId = 0; + ItemSuffixFactor = 0; + } + + VoidStorageItem(uint64 id, uint32 entry, uint32 creator, uint32 randomPropertyId, uint32 suffixFactor) + { + ItemId = id; + ItemEntry = entry; + CreatorGuid = creator; + ItemRandomPropertyId = randomPropertyId; + ItemSuffixFactor = suffixFactor; + } + + uint64 ItemId; + uint32 ItemEntry; + uint32 CreatorGuid; + uint32 ItemRandomPropertyId; + uint32 ItemSuffixFactor; +}; + class TradeData { public: // constructors @@ -1010,8 +1109,8 @@ class TradeData Item* GetSpellCastItem() const; bool HasSpellCastItem() const { return m_spellCastItem != 0; } - uint32 GetMoney() const { return m_money; } - void SetMoney(uint32 money); + uint64 GetMoney() const { return m_money; } + void SetMoney(uint64 money); bool IsAccepted() const { return m_accepted; } void SetAccepted(bool state, bool crosssend = false); @@ -1031,7 +1130,7 @@ class TradeData bool m_accepted; // m_player press accept for trade list bool m_acceptProccess; // one from player/trader press accept and this processed - uint32 m_money; // m_player place money to trade + uint64 m_money; // m_player place money to trade uint32 m_spell; // m_player apply spell to non-traded slot item uint64 m_spellCastItem; // applied spell cast by item use @@ -1039,6 +1138,15 @@ class TradeData uint64 m_items[TRADE_SLOT_COUNT]; // traded items from m_player side including non-traded slot }; +struct ResurrectionData +{ + uint64 GUID; + WorldLocation Location; + uint32 Health; + uint32 Mana; + uint32 Aura; +}; + class KillRewarder { public: @@ -1071,6 +1179,50 @@ private: bool _isPvP; }; +struct PlayerTalentInfo +{ + PlayerTalentInfo() : + FreeTalentPoints(0), UsedTalentCount(0), QuestRewardedTalentCount(0), + ResetTalentsCost(0), ResetTalentsTime(0), + ActiveSpec(0), SpecsCount(1) + { + for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + { + SpecInfo[i].Talents = new PlayerTalentMap(); + memset(SpecInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32)); + SpecInfo[i].TalentTree = 0; + } + } + + ~PlayerTalentInfo() + { + for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + { + for (PlayerTalentMap::const_iterator itr = SpecInfo[i].Talents->begin(); itr != SpecInfo[i].Talents->end(); ++itr) + delete itr->second; + delete SpecInfo[i].Talents; + } + } + + struct TalentSpecInfo + { + PlayerTalentMap* Talents; + uint32 Glyphs[MAX_GLYPH_SLOT_INDEX]; + uint32 TalentTree; + } SpecInfo[MAX_TALENT_SPECS]; + + uint32 FreeTalentPoints; + uint32 UsedTalentCount; + uint32 QuestRewardedTalentCount; + uint32 ResetTalentsCost; + time_t ResetTalentsTime; + uint8 ActiveSpec; + uint8 SpecsCount; + +private: + PlayerTalentInfo(PlayerTalentInfo const&); +}; + class Player : public Unit, public GridObject<Player> { friend class WorldSession; @@ -1103,13 +1255,12 @@ class Player : public Unit, public GridObject<Player> void Update(uint32 time); - static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data); + static bool BuildEnumData(PreparedQueryResult result, ByteBuffer* dataBuffer, ByteBuffer* bitBuffer); void SetInWater(bool apply); bool IsInWater() const { return m_isInWater; } bool IsUnderWater() const; - bool IsFalling() { return GetPositionZ() < m_lastFallZ; } void SendInitialPacketsBeforeAddToMap(); void SendInitialPacketsAfterAddToMap(); @@ -1149,8 +1300,6 @@ class Player : public Unit, public GridObject<Player> void SetTaxiCheater(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_TAXICHEAT; else m_ExtraFlags &= ~PLAYER_EXTRA_TAXICHEAT; } bool isGMVisible() const { return !(m_ExtraFlags & PLAYER_EXTRA_GM_INVISIBLE); } void SetGMVisible(bool on); - bool Has310Flyer(bool checkAllSpells, uint32 excludeSpellId = 0); - void SetHas310Flyer(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_HAS_310_FLYER; else m_ExtraFlags &= ~PLAYER_EXTRA_HAS_310_FLYER; } void SetPvPDeath(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_PVP_DEATH; else m_ExtraFlags &= ~PLAYER_EXTRA_PVP_DEATH; } void GiveXP(uint32 xp, Unit* victim, float group_rate=1.0f); @@ -1191,7 +1340,6 @@ class Player : public Unit, public GridObject<Player> Pet* GetPet() const; Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime); void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false); - uint32 GetPhaseMaskForSpawn() const; // used for proper set phase for DB at GM-mode creature/GO spawn /// Handles said message in regular chat based on declared language and in config pre-defined Range. void Say(std::string const& text, const uint32 language); @@ -1201,6 +1349,7 @@ class Player : public Unit, public GridObject<Player> void TextEmote(std::string const& text); /// Handles whispers from Addons and players based on sender, receiver's guid and language. void Whisper(std::string const& text, const uint32 language, uint64 receiver); + void WhisperAddon(std::string const& text, std::string const& prefix, Player* receiver); /*********************************************************/ /*** STORAGE SYSTEM ***/ @@ -1271,11 +1420,36 @@ class Player : public Unit, public GridObject<Player> void AddRefundReference(uint32 it); void DeleteRefundReference(uint32 it); + /// send initialization of new currency for client + void SendNewCurrency(uint32 id) const; + /// send full data about all currencies to client + void SendCurrencies() const; + /// send conquest currency points and their cap week/arena + void SendPvpRewards() const; + /// return count of currency witch has plr + uint32 GetCurrency(uint32 id, bool usePrecision) const; + /// return count of currency gaind on current week + uint32 GetCurrencyOnWeek(uint32 id, bool usePrecision) const; + /// return week cap by currency id + uint32 GetCurrencyWeekCap(uint32 id, bool usePrecision) const; + /// return presence related currency + bool HasCurrency(uint32 id, uint32 count) const; + /// initialize currency count for custom initialization at create character + void SetCurrency(uint32 id, uint32 count, bool printLog = true); + void ResetCurrencyWeekCap(); + + /** + * @name ModifyCurrency + * @brief Change specific currency and send result to client + + * @param id currency entry from CurrencyTypes.dbc + * @param count integer value for adding/removing curent currency + * @param printLog used on SMSG_UPDATE_CURRENCY + * @param ignore gain multipliers + */ + void ModifyCurrency(uint32 id, int32 count, bool printLog = true, bool ignoreMultipliers = false); + void ApplyEquipCooldown(Item* pItem); - void SetAmmo(uint32 item); - void RemoveAmmo(); - float GetAmmoDPS() const { return m_ammoDPS; } - bool CheckAmmoCompatibility(const ItemTemplate* ammo_proto) const; void QuickEquipItem(uint16 pos, Item* pItem); void VisualizeItem(uint8 slot, Item* pItem); void SetVisibleItemSlot(uint8 slot, Item* pItem); @@ -1296,10 +1470,9 @@ class Player : public Unit, public GridObject<Player> void AddItemToBuyBackSlot(Item* pItem); Item* GetItemFromBuyBackSlot(uint32 slot); void RemoveItemFromBuyBackSlot(uint32 slot, bool del); - uint32 GetMaxKeyringSize() const { return KEYRING_SLOT_END-KEYRING_SLOT_START; } void SendEquipError(InventoryResult msg, Item* pItem, Item* pItem2 = NULL, uint32 itemid = 0); void SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 param); - void SendSellError(SellResult msg, Creature* creature, uint64 guid, uint32 param); + void SendSellError(SellResult msg, Creature* creature, uint64 guid); void AddWeaponProficiency(uint32 newflag) { m_WeaponProficiency |= newflag; } void AddArmorProficiency(uint32 newflag) { m_ArmorProficiency |= newflag; } uint32 GetWeaponProficiency() const { return m_WeaponProficiency; } @@ -1308,6 +1481,7 @@ class Player : public Unit, public GridObject<Player> bool IsTwoHandUsed() const; void SendNewItem(Item* item, uint32 count, bool received, bool created, bool broadcast = false); bool BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot); + bool BuyCurrencyFromVendorSlot(uint64 vendorGuid, uint32 vendorSlot, uint32 currency, uint32 count); bool _StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore); float GetReputationPriceDiscount(Creature const* creature) const; @@ -1327,6 +1501,7 @@ class Player : public Unit, public GridObject<Player> void AddEnchantmentDuration(Item* item, EnchantmentSlot slot, uint32 duration); void ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool apply_dur = true, bool ignore_condition = false); void ApplyEnchantment(Item* item, bool apply); + void ApplyReforgeEnchantment(Item* item, bool apply); void UpdateSkillEnchantments(uint16 skill_id, uint16 curr_value, uint16 new_value); void SendEnchantmentDurations(); void BuildEnchantmentsInfoData(WorldPacket* data); @@ -1441,14 +1616,13 @@ class Player : public Unit, public GridObject<Player> void UpdateForQuestWorldObjects(); bool CanShareQuest(uint32 questId) const; - void SendQuestComplete(uint32 questId); + void SendQuestComplete(Quest const* quest); void SendQuestReward(Quest const* quest, uint32 XP); void SendQuestFailed(uint32 questId, InventoryResult reason = EQUIP_ERR_OK); void SendQuestTimerFailed(uint32 questId); void SendCanTakeQuestResponse(QuestFailedReason msg) const; void SendQuestConfirmAccept(Quest const* quest, Player* pReceiver); void SendPushToPartyResponse(Player* player, uint8 msg); - void SendQuestUpdateAddItem(Quest const* quest, uint32 itemIdx, uint16 count); void SendQuestUpdateAddCreatureOrGo(Quest const* quest, uint64 guid, uint32 creatureOrGOIdx, uint16 oldCount, uint16 addCount); void SendQuestUpdateAddPlayer(Quest const* quest, uint16 oldCount, uint16 addCount); @@ -1461,6 +1635,17 @@ class Player : public Unit, public GridObject<Player> void AddTimedQuest(uint32 questId) { m_timedquests.insert(questId); } void RemoveTimedQuest(uint32 questId) { m_timedquests.erase(questId); } + void SaveCUFProfile(uint8 id, CUFProfile* profile) { delete _CUFProfiles[id]; _CUFProfiles[id] = profile; } ///> Replaces a CUF profile at position 0-4 + CUFProfile* GetCUFProfile(uint8 id) const { return _CUFProfiles[id]; } ///> Retrieves a CUF profile at position 0-4 + uint8 GetCUFProfilesCount() const + { + uint8 count = 0; + for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) + if (_CUFProfiles[i]) + ++count; + return count; + } + bool HasPvPForcingQuest() const; /*********************************************************/ @@ -1478,6 +1663,8 @@ class Player : public Unit, public GridObject<Player> static bool LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, uint64 guid); static bool IsValidGender(uint8 Gender) { return Gender <= GENDER_FEMALE; } + static bool IsValidClass(uint8 Class) { return ((1 << (Class - 1)) & CLASSMASK_ALL_PLAYABLE) != 0; } + static bool IsValidRace(uint8 Race) { return ((1 << (Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0; } /*********************************************************/ /*** SAVE SYSTEM ***/ @@ -1509,11 +1696,11 @@ class Player : public Unit, public GridObject<Player> void setRegenTimerCount(uint32 time) {m_regenTimerCount = time;} void setWeaponChangeTimer(uint32 time) {m_weaponChangeTimer = time;} - uint32 GetMoney() const { return GetUInt32Value(PLAYER_FIELD_COINAGE); } - bool ModifyMoney(int32 amount, bool sendError = true); - bool HasEnoughMoney(uint32 amount) const { return (GetMoney() >= amount); } - bool HasEnoughMoney(int32 amount) const; - void SetMoney(uint32 value); + uint64 GetMoney() const { return GetUInt64Value(PLAYER_FIELD_COINAGE); } + bool ModifyMoney(int64 amount, bool sendError = true); + bool HasEnoughMoney(uint64 amount) const { return (GetMoney() >= amount); } + bool HasEnoughMoney(int64 amount) const; + void SetMoney(uint64 value); RewardedQuestSet const& getRewardedQuests() const { return m_RewardedQuests; } QuestStatusMap& getQuestStatusMap() { return m_QuestStatus; } @@ -1576,6 +1763,7 @@ class Player : public Unit, public GridObject<Player> TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const; bool IsSpellFitByClassAndRace(uint32 spell_id) const; bool IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const; + bool IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const; void SendProficiency(ItemClass itemClass, uint32 itemSubclassMask); void SendInitialSpells(); @@ -1593,39 +1781,55 @@ class Player : public Unit, public GridObject<Player> void RemoveTemporarySpell(uint32 spellId); void SetReputation(uint32 factionentry, uint32 value); uint32 GetReputation(uint32 factionentry) const; - std::string const& GetGuildName(); - uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); } - void SetFreeTalentPoints(uint32 points); + std::string GetGuildName(); + + // Talents + uint32 GetFreeTalentPoints() const { return _talentMgr->FreeTalentPoints; } + void SetFreeTalentPoints(uint32 points) { _talentMgr->FreeTalentPoints = points; } + uint32 GetUsedTalentCount() const { return _talentMgr->UsedTalentCount; } + void SetUsedTalentCount(uint32 talents) { _talentMgr->UsedTalentCount = talents; } + uint32 GetQuestRewardedTalentCount() const { return _talentMgr->QuestRewardedTalentCount; } + void AddQuestRewardedTalentCount(uint32 points) { _talentMgr->QuestRewardedTalentCount += points; } + uint32 GetTalentResetCost() const { return _talentMgr->ResetTalentsCost; } + void SetTalentResetCost(uint32 cost) { _talentMgr->ResetTalentsCost = cost; } + uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; } + void SetTalentResetTime(time_t time_) { _talentMgr->ResetTalentsTime = time_; } + uint32 GetPrimaryTalentTree(uint8 spec) const { return _talentMgr->SpecInfo[spec].TalentTree; } + void SetPrimaryTalentTree(uint8 spec, uint32 tree) { _talentMgr->SpecInfo[spec].TalentTree = tree; } + uint8 GetActiveSpec() const { return _talentMgr->ActiveSpec; } + void SetActiveSpec(uint8 spec){ _talentMgr->ActiveSpec = spec; } + uint8 GetSpecsCount() const { return _talentMgr->SpecsCount; } + void SetSpecsCount(uint8 count) { _talentMgr->SpecsCount = count; } + bool ResetTalents(bool no_cost = false); - uint32 ResetTalentsCost() const; + uint32 GetNextResetTalentsCost() const; void InitTalentForLevel(); void BuildPlayerTalentsInfoData(WorldPacket* data); void BuildPetTalentsInfoData(WorldPacket* data); void SendTalentsInfoData(bool pet); - void LearnTalent(uint32 talentId, uint32 talentRank); + bool LearnTalent(uint32 talentId, uint32 talentRank); void LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank); - bool AddTalent(uint32 spellId, uint8 spec, bool learning); bool HasTalent(uint32 spell_id, uint8 spec) const; - uint32 CalculateTalentsPoints() const; // Dual Spec void UpdateSpecCount(uint8 count); - uint32 GetActiveSpec() { return m_activeSpec; } - void SetActiveSpec(uint8 spec){ m_activeSpec = spec; } - uint8 GetSpecsCount() { return m_specsCount; } - void SetSpecsCount(uint8 count) { m_specsCount = count; } void ActivateSpec(uint8 spec); void InitGlyphsForLevel(); void SetGlyphSlot(uint8 slot, uint32 slottype) { SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot, slottype); } - uint32 GetGlyphSlot(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); } + + uint32 GetGlyphSlot(uint8 slot) const { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); } void SetGlyph(uint8 slot, uint32 glyph); - uint32 GetGlyph(uint8 slot) { return m_Glyphs[m_activeSpec][slot]; } + uint32 GetGlyph(uint8 spec, uint8 slot) const { return _talentMgr->SpecInfo[spec].Glyphs[slot]; } - uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS2); } - void SetFreePrimaryProfessions(uint16 profs) { SetUInt32Value(PLAYER_CHARACTER_POINTS2, profs); } + PlayerTalentMap const* GetTalentMap(uint8 spec) const { return _talentMgr->SpecInfo[spec].Talents; } + PlayerTalentMap* GetTalentMap(uint8 spec) { return _talentMgr->SpecInfo[spec].Talents; } + ActionButtonList const& GetActionButtons() const { return m_actionButtons; } + + uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS); } + void SetFreePrimaryProfessions(uint16 profs) { SetUInt32Value(PLAYER_CHARACTER_POINTS, profs); } void InitPrimaryProfessions(); PlayerSpellMap const& GetSpellMap() const { return m_spells; } @@ -1654,6 +1858,7 @@ class Player : public Unit, public GridObject<Player> void RemoveSpellCooldown(uint32 spell_id, bool update = false); void RemoveSpellCategoryCooldown(uint32 cat, bool update = false); void SendClearCooldown(uint32 spell_id, Unit* target); + void SendClearAllCooldowns(Unit* target); GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } @@ -1666,10 +1871,22 @@ class Player : public Unit, public GridObject<Player> void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; } void UpdatePotionCooldown(Spell* spell = NULL); - void setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana); - void clearResurrectRequestData() { setResurrectRequestData(0, 0, 0.0f, 0.0f, 0.0f, 0, 0); } - bool isResurrectRequestedBy(uint64 guid) const { return m_resurrectGUID == guid; } - bool isResurrectRequested() const { return m_resurrectGUID != 0; } + void SetResurrectRequestData(Unit* caster, uint32 health, uint32 mana, uint32 appliedAura); + void ClearResurrectRequestData() + { + delete _resurrectionData; + _resurrectionData = NULL; + } + + bool IsResurrectRequestedBy(uint64 guid) const + { + if (!IsResurrectRequested()) + return false; + + return _resurrectionData->GUID == guid; + } + + bool IsResurrectRequested() const { return _resurrectionData != NULL; } void ResurrectUsingRequestData(); uint8 getCinematic() { return m_cinematic; } @@ -1678,7 +1895,7 @@ class Player : public Unit, public GridObject<Player> ActionButton* addActionButton(uint8 button, uint32 action, uint8 type); void removeActionButton(uint8 button); ActionButton const* GetActionButton(uint8 button); - void SendInitialActionButtons() const { SendActionButtons(1); } + void SendInitialActionButtons() const { SendActionButtons(0); } void SendActionButtons(uint32 state) const; bool IsActionButtonDataValid(uint8 button, uint32 action, uint8 type); @@ -1714,11 +1931,13 @@ class Player : public Unit, public GridObject<Player> void RemoveFromGroup(RemoveMethod method = GROUP_REMOVEMETHOD_DEFAULT) { RemoveFromGroup(GetGroup(), GetGUID(), method); } void SendUpdateToOutOfRangeGroupMembers(); - void SetInGuild(uint32 GuildId) { SetUInt32Value(PLAYER_GUILDID, GuildId); } + void SetInGuild(uint32 guildId); void SetRank(uint8 rankId) { SetUInt32Value(PLAYER_GUILDRANK, rankId); } uint8 GetRank() const { return uint8(GetUInt32Value(PLAYER_GUILDRANK)); } + void SetGuildLevel(uint32 level) { SetUInt32Value(PLAYER_GUILDLEVEL, level); } + uint32 GetGuildLevel() { return GetUInt32Value(PLAYER_GUILDLEVEL); } void SetGuildIdInvited(uint32 GuildId) { m_GuildIdInvited = GuildId; } - uint32 GetGuildId() const { return GetUInt32Value(PLAYER_GUILDID); } + uint32 GetGuildId() const { return GetUInt32Value(OBJECT_FIELD_DATA); /* return only lower part */ } Guild* GetGuild(); static uint32 GetGuildIdFromDB(uint64 guid); static uint8 GetRankFromDB(uint64 guid); @@ -1734,6 +1953,7 @@ class Player : public Unit, public GridObject<Player> uint32 GetArenaPersonalRating(uint8 slot) const { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING); } void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; } uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; } + uint32 GetRBGPersonalRating() const { return 0; } Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; } Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; } @@ -1744,15 +1964,12 @@ class Player : public Unit, public GridObject<Player> void StoreRaidMapDifficulty() { m_raidMapDifficulty = GetMap()->GetDifficulty(); } bool UpdateSkill(uint32 skill_id, uint32 step); - bool UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step); + bool UpdateSkillPro(uint16 skillId, int32 chance, uint32 step); bool UpdateCraftSkill(uint32 spellid); bool UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator = 1); bool UpdateFishingSkill(); - uint32 GetBaseDefenseSkillValue() const { return GetBaseSkillValue(SKILL_DEFENSE); } - uint32 GetBaseWeaponSkillValue(WeaponAttackType attType) const; - uint32 GetSpellByProto(ItemTemplate* proto); float GetHealthBonusFromStamina(); @@ -1765,27 +1982,26 @@ class Player : public Unit, public GridObject<Player> void UpdateArmor(); void UpdateMaxHealth(); void UpdateMaxPower(Powers power); - void ApplyFeralAPBonus(int32 amount, bool apply); void UpdateAttackPowerAndDamage(bool ranged = false); - void UpdateShieldBlockValue(); void ApplySpellPowerBonus(int32 amount, bool apply); void UpdateSpellDamageAndHealingBonus(); void ApplyRatingMod(CombatRating cr, int32 value, bool apply); void UpdateRating(CombatRating cr); void UpdateAllRatings(); + void UpdateMastery(); + bool CanUseMastery() const; void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) override; - void UpdateDefenseBonusesMod(); inline void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);} float GetMeleeCritFromAgility(); void GetDodgeFromAgility(float &diminishing, float &nondiminishing); - float GetMissPercentageFromDefence() const; float GetSpellCritFromIntellect(); - float OCTRegenHPPerSpirit(); float OCTRegenMPPerSpirit(); float GetRatingMultiplier(CombatRating cr) const; float GetRatingBonusValue(CombatRating cr) const; + + /// Returns base spellpower bonus from spellpower stat on items, without spellpower from intellect stat uint32 GetBaseSpellPowerBonus() const { return m_baseSpellPower; } int32 GetSpellPenetrationItemMod() const { return m_spellPenetrationItemMod; } @@ -1807,6 +2023,7 @@ class Player : public Unit, public GridObject<Player> void ApplyHealthRegenBonus(int32 amount, bool apply); void UpdateManaRegen(); void UpdateRuneRegen(RuneType rune); + void UpdateAllRunesRegen(); uint64 GetLootGUID() const { return m_lootGuid; } void SetLootGUID(uint64 guid) { m_lootGuid = guid; } @@ -1844,8 +2061,6 @@ class Player : public Unit, public GridObject<Player> void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only); void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr); - void SendTeleportAckPacket(); - Corpse* GetCorpse() const; void SpawnCorpseBones(); void CreateCorpse(); @@ -1867,8 +2082,6 @@ class Player : public Unit, public GridObject<Player> void StopMirrorTimers(); bool IsMirrorTimerActive(MirrorTimerType type); - void SetMovement(PlayerMovementType pType); - bool CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone); void JoinedChannel(Channel* c); @@ -1877,10 +2090,6 @@ class Player : public Unit, public GridObject<Player> void UpdateLocalChannels(uint32 newZone); void LeaveLFGChannel(); - void UpdateDefense(); - void UpdateWeaponSkill (WeaponAttackType attType); - void UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool defence); - void SetSkill(uint16 id, uint16 step, uint16 currVal, uint16 maxVal); uint16 GetMaxSkillValue(uint32 skill) const; // max + perm. bonus + temp bonus uint16 GetPureMaxSkillValue(uint32 skill) const; // max @@ -1914,7 +2123,7 @@ class Player : public Unit, public GridObject<Player> bool IsAtRecruitAFriendDistance(WorldObject const* pOther) const; void RewardPlayerAndGroupAtKill(Unit* victim, bool isBattleGround); void RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewardSource); - bool isHonorOrXPTarget(Unit* victim) const; + bool isHonorOrXPTarget(Unit const* victim) const; bool GetsRecruitAFriendBonus(bool forXP); uint8 GetGrantableLevels() { return m_grantableLevels; } @@ -1935,15 +2144,10 @@ class Player : public Unit, public GridObject<Player> /*********************************************************/ /*** PVP SYSTEM ***/ /*********************************************************/ + // TODO: Properly implement correncies as of Cataclysm void UpdateHonorFields(); bool RewardHonor(Unit* victim, uint32 groupsize, int32 honor = -1, bool pvptoken = false); - uint32 GetHonorPoints() const { return GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY); } - uint32 GetArenaPoints() const { return GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY); } - void ModifyHonorPoints(int32 value, SQLTransaction trans = SQLTransaction(nullptr)); //! If trans is specified, honor save query will be added to trans - void ModifyArenaPoints(int32 value, SQLTransaction trans = SQLTransaction(nullptr)); //! If trans is specified, arena point save query will be added to trans uint32 GetMaxPersonalArenaRatingRequirement(uint32 minarenaslot) const; - void SetHonorPoints(uint32 value); - void SetArenaPoints(uint32 value); //End of PvP System @@ -1959,7 +2163,7 @@ class Player : public Unit, public GridObject<Player> int32 CalculateCorpseReclaimDelay(bool load = false); void SendCorpseReclaimDelay(uint32 delay); - uint32 GetShieldBlockValue() const; // overwrite Unit version (virtual) + uint32 GetBlockPercent() const { return GetUInt32Value(PLAYER_SHIELD_BLOCK); } bool CanParry() const { return m_canParry; } void SetCanParry(bool value); bool CanBlock() const { return m_canBlock; } @@ -1989,7 +2193,6 @@ class Player : public Unit, public GridObject<Player> void _ApplyAllLevelScaleItemMods(bool apply); void _ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply, bool only_level_scale = false); void _ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv, bool apply); - void _ApplyAmmoBonuses(); bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot); void ToggleMetaGemsActive(uint8 exceptslot, bool apply); void CorrectMetaGemEnchants(uint8 slot, bool apply); @@ -2032,6 +2235,16 @@ class Player : public Unit, public GridObject<Player> BattlegroundTypeId GetBattlegroundTypeId() const { return m_bgData.bgTypeID; } Battleground* GetBattleground() const; + uint32 GetBattlegroundQueueJoinTime(uint32 bgTypeId) const { return m_bgData.bgQueuesJoinedTime.find(bgTypeId)->second; } + void AddBattlegroundQueueJoinTime(uint32 bgTypeId, uint32 joinTime) + { + m_bgData.bgQueuesJoinedTime[bgTypeId] = joinTime; + } + void RemoveBattlegroundQueueJoinTime(uint32 bgTypeId) + { + m_bgData.bgQueuesJoinedTime.erase(m_bgData.bgQueuesJoinedTime.find(bgTypeId)->second); + } + bool InBattlegroundQueue() const; BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const; @@ -2157,6 +2370,8 @@ class Player : public Unit, public GridObject<Player> void UpdateVisibilityOf(WorldObject* target); void UpdateTriggerVisibility(); + void UpdatePhasing(); + template<class T> void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow); @@ -2257,7 +2472,8 @@ class Player : public Unit, public GridObject<Player> RuneType GetBaseRune(uint8 index) const { return RuneType(m_runes->runes[index].BaseRune); } RuneType GetCurrentRune(uint8 index) const { return RuneType(m_runes->runes[index].CurrentRune); } uint32 GetRuneCooldown(uint8 index) const { return m_runes->runes[index].Cooldown; } - uint32 GetRuneBaseCooldown(uint8 index); + uint32 GetRuneBaseCooldown(uint8 index) const { return GetRuneTypeBaseCooldown(GetBaseRune(index)); } + uint32 GetRuneTypeBaseCooldown(RuneType runeType) const; bool IsBaseRuneSlotsOnCooldown(RuneType runeType) const; RuneType GetLastUsedRune() { return m_runes->lastUsedRune; } void SetLastUsedRune(RuneType type) { m_runes->lastUsedRune = type; } @@ -2274,11 +2490,12 @@ class Player : public Unit, public GridObject<Player> void InitRunes(); void SendRespondInspectAchievements(Player* player) const; + uint32 GetAchievementPoints() const; bool HasAchieved(uint32 achievementId) const; void ResetAchievements(); void CheckAllAchievementCriteria(); - void ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, bool evenIfCriteriaComplete = false); - void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, Unit* unit = NULL); + void ResetAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, bool evenIfCriteriaComplete = false); + void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1 = 0, uint64 miscValue2 = 0, uint64 miscValue3 = 0, Unit* unit = NULL); void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0); void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); void CompletedAchievement(AchievementEntry const* entry); @@ -2302,11 +2519,13 @@ class Player : public Unit, public GridObject<Player> bool IsInWhisperWhiteList(uint64 guid); void RemoveFromWhisperWhiteList(uint64 guid) { WhisperList.remove(guid); } - bool SetDisableGravity(bool disable, bool packetOnly /* = false */); - bool SetCanFly(bool apply); - bool SetWaterWalking(bool apply, bool packetOnly = false); - bool SetFeatherFall(bool apply, bool packetOnly = false); - bool SetHover(bool enable, bool packetOnly = false); + void ReadMovementInfo(WorldPacket& data, MovementInfo* mi, Movement::ExtraMovementStatusElement* extras = NULL); + + /*! These methods send different packets to the client in apply and unapply case. + These methods are only sent to the current unit. + */ + void SendMovementSetCanTransitionBetweenSwimAndFly(bool apply); + void SendMovementSetCollisionHeight(float height); bool CanFly() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); } @@ -2318,11 +2537,26 @@ class Player : public Unit, public GridObject<Player> bool IsLoading() const; + // Void Storage + bool IsVoidStorageUnlocked() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } + void UnlockVoidStorage() { SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } + void LockVoidStorage() { RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } + uint8 GetNextVoidStorageFreeSlot() const; + uint8 GetNumOfVoidStorageFreeSlots() const; + uint8 AddVoidStorageItem(const VoidStorageItem& item); + void AddVoidStorageItemAtSlot(uint8 slot, const VoidStorageItem& item); + void DeleteVoidStorageItem(uint8 slot); + bool SwapVoidStorageItem(uint8 oldSlot, uint8 newSlot); + VoidStorageItem* GetVoidStorageItem(uint8 slot) const; + VoidStorageItem* GetVoidStorageItem(uint64 id, uint8& slot) const; + protected: // Gamemaster whisper whitelist WhisperListContainer WhisperList; uint32 m_regenTimerCount; - float m_powerFraction[MAX_POWERS]; + uint32 m_holyPowerRegenTimerCount; + uint32 m_focusRegenTimerCount; + float m_powerFraction[MAX_POWERS_PER_CLASS]; uint32 m_contestedPvPTimer; /*********************************************************/ @@ -2368,6 +2602,7 @@ class Player : public Unit, public GridObject<Player> void _LoadGlyphAuras(); void _LoadBoundInstances(PreparedQueryResult result); void _LoadInventory(PreparedQueryResult result, uint32 timeDiff); + void _LoadVoidStorage(PreparedQueryResult result); void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery); void _LoadMail(); void _LoadMailedItems(Mail* mail); @@ -2390,6 +2625,8 @@ class Player : public Unit, public GridObject<Player> void _LoadGlyphs(PreparedQueryResult result); void _LoadTalents(PreparedQueryResult result); void _LoadInstanceTimeRestrictions(PreparedQueryResult result); + void _LoadCurrency(PreparedQueryResult result); + void _LoadCUFProfiles(PreparedQueryResult result); /*********************************************************/ /*** SAVE SYSTEM ***/ @@ -2398,6 +2635,7 @@ class Player : public Unit, public GridObject<Player> void _SaveActions(SQLTransaction& trans); void _SaveAuras(SQLTransaction& trans); void _SaveInventory(SQLTransaction& trans); + void _SaveVoidStorage(SQLTransaction& trans); void _SaveMail(SQLTransaction& trans); void _SaveQuestStatus(SQLTransaction& trans); void _SaveDailyQuestStatus(SQLTransaction& trans); @@ -2412,6 +2650,8 @@ class Player : public Unit, public GridObject<Player> void _SaveTalents(SQLTransaction& trans); void _SaveStats(SQLTransaction& trans); void _SaveInstanceTimeRestrictions(SQLTransaction& trans); + void _SaveCurrency(SQLTransaction& trans); + void _SaveCUFProfiles(SQLTransaction& trans); /*********************************************************/ /*** ENVIRONMENTAL SYSTEM ***/ @@ -2443,6 +2683,29 @@ class Player : public Unit, public GridObject<Player> Item* m_items[PLAYER_SLOTS_COUNT]; uint32 m_currentBuybackSlot; + PlayerCurrenciesMap _currencyStorage; + + /** + * @name GetCurrencyWeekCap + * @brief return week cap for selected currency + + * @param CurrencyTypesEntry for which to retrieve weekly cap + */ + uint32 GetCurrencyWeekCap(CurrencyTypesEntry const* currency) const; + + /* + * @name GetCurrencyTotalCap + * @brief return total cap for selected currency + + * @param CurrencyTypesEntry for which to retrieve total cap + */ + uint32 GetCurrencyTotalCap(CurrencyTypesEntry const* currency) const; + + /// Updates weekly conquest point cap (dynamic cap) + void UpdateConquestCurrencyCap(uint32 currency); + + VoidStorageItem* _voidStorageItems[VOID_STORAGE_MAX_SLOT]; + std::vector<Item*> m_itemUpdateQueue; bool m_itemUpdateQueueBlocked; @@ -2464,22 +2727,17 @@ class Player : public Unit, public GridObject<Player> PlayerMails m_mail; PlayerSpellMap m_spells; - PlayerTalentMap* m_talents[MAX_TALENT_SPECS]; uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use GlobalCooldownMgr m_GlobalCooldownMgr; - uint8 m_activeSpec; - uint8 m_specsCount; - - uint32 m_Glyphs[MAX_TALENT_SPECS][MAX_GLYPH_SLOT_INDEX]; + PlayerTalentInfo* _talentMgr; ActionButtonList m_actionButtons; float m_auraBaseMod[BASEMOD_END][MOD_END]; int16 m_baseRatingValue[MAX_COMBAT_RATING]; uint32 m_baseSpellPower; - uint32 m_baseFeralAP; uint32 m_baseManaRegen; uint32 m_baseHealthRegen; int32 m_spellPenetrationItemMod; @@ -2493,10 +2751,7 @@ class Player : public Unit, public GridObject<Player> void ResetTimeSync(); void SendTimeSync(); - uint64 m_resurrectGUID; - uint32 m_resurrectMap; - float m_resurrectX, m_resurrectY, m_resurrectZ; - uint32 m_resurrectHealth, m_resurrectMana; + ResurrectionData* _resurrectionData; WorldSession* m_session; @@ -2531,7 +2786,6 @@ class Player : public Unit, public GridObject<Player> bool m_canBlock; bool m_canTitanGrip; uint8 m_swingErrorMsg; - float m_ammoDPS; ////////////////////Rest System///////////////////// time_t time_inn_enter; @@ -2542,10 +2796,6 @@ class Player : public Unit, public GridObject<Player> float m_rest_bonus; RestType rest_type; ////////////////////Rest System///////////////////// - uint32 m_resetTalentsCost; - time_t m_resetTalentsTime; - uint32 m_usedTalentCount; - uint32 m_questRewardTalentCount; // Social PlayerSocial *m_social; @@ -2580,6 +2830,8 @@ class Player : public Unit, public GridObject<Player> bool m_needsZoneUpdate; + CUFProfile* _CUFProfiles[MAX_CUF_PROFILES]; + private: // internal common parts for CanStore/StoreItem functions InventoryResult CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemTemplate const* pProto, uint32& count, bool swap, Item* pSrcItem) const; @@ -2591,6 +2843,7 @@ class Player : public Unit, public GridObject<Player> std::set<uint32> m_refundableItems; void SendRefundInfo(Item* item); void RefundItem(Item* item); + void SendItemRefundResult(Item* item, ItemExtendedCostEntry const* iece, uint8 error); // know currencies are not removed at any point (0 displayed) void AddKnownCurrency(uint32 itemId); @@ -2629,14 +2882,14 @@ class Player : public Unit, public GridObject<Player> uint32 m_temporaryUnsummonedPetNumber; uint32 m_oldpetspell; - AchievementMgr* m_achievementMgr; + AchievementMgr<Player>* m_achievementMgr; ReputationMgr* m_reputationMgr; SpellCooldowns m_spellCooldowns; uint32 m_ChampioningFaction; - uint32 m_timeSyncCounter; + std::queue<uint32> m_timeSyncQueue; uint32 m_timeSyncTimer; uint32 m_timeSyncClient; uint32 m_timeSyncServer; @@ -2646,6 +2899,7 @@ class Player : public Unit, public GridObject<Player> uint32 _pendingBindTimer; uint32 _activeCheats; + uint32 _maxPersonalArenaRate; }; void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index f2c2ada5666..c351aeac482 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -26,6 +26,7 @@ #include "World.h" #include "Util.h" #include "AccountMgr.h" +#include "WorldSession.h" PlayerSocial::PlayerSocial(): m_playerGUID() { } diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp index b8f5fd1833d..92aa34371f8 100644 --- a/src/server/game/Entities/Totem/Totem.cpp +++ b/src/server/game/Entities/Totem/Totem.cpp @@ -74,12 +74,9 @@ void Totem::InitStats(uint32 duration) // Get spell cast by totem if (SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(GetSpell())) - if (totemSpell->CalcCastTime()) // If spell has cast time -> its an active totem + if (totemSpell->CalcCastTime(getLevel())) // If spell has cast time -> its an active totem m_type = TOTEM_ACTIVE; - if (GetEntry() == SENTRY_TOTEM_ENTRY) - SetReactState(REACT_AGGRESSIVE); - m_duration = duration; SetLevel(GetOwner()->getLevel()); @@ -88,13 +85,14 @@ void Totem::InitStats(uint32 duration) void Totem::InitSummon() { if (m_type == TOTEM_PASSIVE && GetSpell()) - { CastSpell(this, GetSpell(), true); - } // Some totems can have both instant effect and passive spell if (GetSpell(1)) CastSpell(this, GetSpell(1), true); + + if (m_Properties->Id == SUMMON_TYPE_TOTEM_FIRE && GetOwner()->HasAura(SPELL_TOTEMIC_WRATH_TALENT)) + CastSpell(this, SPELL_TOTEMIC_WRATH, true); } void Totem::UnSummon(uint32 msTime) @@ -120,11 +118,7 @@ void Totem::UnSummon(uint32 msTime) GetOwner()->RemoveAurasDueToSpell(GetSpell(), GetGUID()); - // Remove Sentry Totem Aura - if (GetEntry() == SENTRY_TOTEM_ENTRY) - GetOwner()->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID); - - //remove aura all party members too + // remove aura all party members too if (Player* owner = GetOwner()->ToPlayer()) { owner->SendAutoRepeatCancel(this); diff --git a/src/server/game/Entities/Totem/Totem.h b/src/server/game/Entities/Totem/Totem.h index da0398f3a96..5a2f3f5773a 100644 --- a/src/server/game/Entities/Totem/Totem.h +++ b/src/server/game/Entities/Totem/Totem.h @@ -28,9 +28,12 @@ enum TotemType TOTEM_STATUE = 2 // copied straight from MaNGOS, may need more implementation to work }; // Some Totems cast spells that are not in creature DB -#define SENTRY_TOTEM_SPELLID 6495 - -#define SENTRY_TOTEM_ENTRY 3968 +enum TotemSpells +{ + // Totemic Wrath + SPELL_TOTEMIC_WRATH_TALENT = 77746, + SPELL_TOTEMIC_WRATH = 77747 +}; class Totem : public Minion { diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index d907274f8d1..0c22caed882 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -229,7 +229,6 @@ void Transport::AddPassenger(WorldObject* passenger) if (_passengers.insert(passenger).second) { passenger->SetTransport(this); - passenger->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_ONTRANSPORT); passenger->m_movementInfo.transport.guid = GetGUID(); TC_LOG_DEBUG("entities.transport", "Object %s boarded transport %s.", passenger->GetName().c_str(), GetName().c_str()); @@ -259,7 +258,6 @@ void Transport::RemovePassenger(WorldObject* passenger) if (erased || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload { passenger->SetTransport(NULL); - passenger->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); passenger->m_movementInfo.transport.Reset(); TC_LOG_DEBUG("entities.transport", "Object %s removed from transport %s.", passenger->GetName().c_str(), GetName().c_str()); @@ -285,7 +283,6 @@ Creature* Transport::CreateNPCPassenger(uint32 guid, CreatureData const* data) float o = data->orientation; creature->SetTransport(this); - creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); creature->m_movementInfo.transport.guid = GetGUID(); creature->m_movementInfo.transport.pos.Relocate(x, y, z, o); CalculatePassengerPosition(x, y, z, &o); @@ -304,6 +301,15 @@ Creature* Transport::CreateNPCPassenger(uint32 guid, CreatureData const* data) return NULL; } + if (data->phaseid) + creature->SetInPhase(data->phaseid, false, true); + else if (data->phaseGroup) + for (auto phase : GetPhasesForGroup(data->phaseGroup)) + creature->SetInPhase(phase, false, true); + else + for (auto phase : GetPhases()) // Set the creature to the transport's phases + creature->SetInPhase(phase, false, true); + if (!map->AddToMap(creature)) { delete creature; @@ -408,9 +414,11 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu } } - uint32 phase = PHASEMASK_NORMAL; + std::set<uint32> phases; if (summoner) - phase = summoner->GetPhaseMask(); + phases = summoner->GetPhases(); + else + phases = GetPhases(); // If there was no summoner, try to use the transport phases TempSummon* summon = NULL; switch (mask) @@ -436,16 +444,18 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu pos.GetPosition(x, y, z, o); CalculatePassengerPosition(x, y, z, &o); - if (!summon->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, phase, entry, x, y, z, o, nullptr, vehId)) + if (!summon->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, 0, entry, x, y, z, o, nullptr, vehId)) { delete summon; return NULL; } + for (auto itr : phases) + summon->SetInPhase(itr, false, true); + summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); summon->SetTransport(this); - summon->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); summon->m_movementInfo.transport.guid = GetGUID(); summon->m_movementInfo.transport.pos.Relocate(pos); summon->Relocate(x, y, z, o); diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index e644417f1ac..7da8c11861c 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -27,7 +27,7 @@ struct CreatureData; class Transport : public GameObject, public TransportBase { - friend Transport* TransportMgr::CreateTransport(uint32, uint32, Map*); + friend Transport* TransportMgr::CreateTransport(uint32, uint32, Map*, uint32, uint32); Transport(); public: diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 04136221d0d..06179692845 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -108,9 +108,6 @@ bool Player::UpdateStats(Stats stat) switch (stat) { - case STAT_STRENGTH: - UpdateShieldBlockValue(); - break; case STAT_AGILITY: UpdateArmor(); UpdateAllCritPercentages(); @@ -131,24 +128,12 @@ bool Player::UpdateStats(Stats stat) } if (stat == STAT_STRENGTH) - { UpdateAttackPowerAndDamage(false); - if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, stat)) - UpdateAttackPowerAndDamage(true); - } else if (stat == STAT_AGILITY) { UpdateAttackPowerAndDamage(false); UpdateAttackPowerAndDamage(true); } - else - { - // Need update (exist AP from stat auras) - if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT, stat)) - UpdateAttackPowerAndDamage(false); - if (HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, stat)) - UpdateAttackPowerAndDamage(true); - } UpdateSpellDamageAndHealingBonus(); UpdateManaRegen(); @@ -208,8 +193,9 @@ bool Player::UpdateAllStats() UpdateAllRatings(); UpdateAllCritPercentages(); UpdateAllSpellCritChances(); - UpdateDefenseBonusesMod(); - UpdateShieldBlockValue(); + UpdateBlockPercentage(); + UpdateParryPercentage(); + UpdateDodgePercentage(); UpdateSpellDamageAndHealingBonus(); UpdateManaRegen(); UpdateExpertise(BASE_ATTACK); @@ -247,7 +233,6 @@ void Player::UpdateArmor() float value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items) value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items - value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats value += GetModifierValue(unitMod, TOTAL_VALUE); //add dynamic flat mods @@ -271,15 +256,21 @@ void Player::UpdateArmor() float Player::GetHealthBonusFromStamina() { + // Taken from PaperDollFrame.lua - 4.3.4.15595 + float ratio = 10.0f; + if (gtOCTHpPerStaminaEntry const* hpBase = sGtOCTHpPerStaminaStore.LookupEntry((getClass() - 1) * GT_MAX_LEVEL + getLevel() - 1)) + ratio = hpBase->ratio; + float stamina = GetStat(STAT_STAMINA); float baseStam = std::min(20.0f, stamina); float moreStam = stamina - baseStam; - return baseStam + (moreStam*10.0f); + return baseStam + moreStam * ratio; } float Player::GetManaBonusFromIntellect() { + // Taken from PaperDollFrame.lua - 4.3.4.15595 float intellect = GetStat(STAT_INTELLECT); float baseInt = std::min(20.0f, intellect); @@ -314,140 +305,32 @@ void Player::UpdateMaxPower(Powers power) SetMaxPower(power, uint32(value)); } -void Player::ApplyFeralAPBonus(int32 amount, bool apply) -{ - _ModifyUInt32(apply, m_baseFeralAP, amount); - UpdateAttackPowerAndDamage(); -} - void Player::UpdateAttackPowerAndDamage(bool ranged) { float val2 = 0.0f; float level = float(getLevel()); + ChrClassesEntry const* entry = sChrClassesStore.LookupEntry(getClass()); UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; uint16 index = UNIT_FIELD_ATTACK_POWER; - uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS; - uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; if (ranged) { index = UNIT_FIELD_RANGED_ATTACK_POWER; - index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS; - index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; - - switch (getClass()) - { - case CLASS_HUNTER: - val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; - break; - case CLASS_ROGUE: - val2 = level + GetStat(STAT_AGILITY) - 10.0f; - break; - case CLASS_WARRIOR: - val2 = level + GetStat(STAT_AGILITY) - 10.0f; - break; - case CLASS_DRUID: - switch (GetShapeshiftForm()) - { - case FORM_CAT: - case FORM_BEAR: - case FORM_DIREBEAR: - val2 = 0.0f; break; - default: - val2 = GetStat(STAT_AGILITY) - 10.0f; break; - } - break; - default: val2 = GetStat(STAT_AGILITY) - 10.0f; break; - } + val2 = (level + std::max(GetStat(STAT_AGILITY) - 10.0f, 0.0f)) * entry->RAPPerAgility; } else { - switch (getClass()) - { - case CLASS_WARRIOR: - val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f; - break; - case CLASS_PALADIN: - val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f; - break; - case CLASS_DEATH_KNIGHT: - val2 = level * 3.0f + GetStat(STAT_STRENGTH) * 2.0f - 20.0f; - break; - case CLASS_ROGUE: - val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; - break; - case CLASS_HUNTER: - val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; - break; - case CLASS_SHAMAN: - val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; - break; - case CLASS_DRUID: - { - // Check if Predatory Strikes is skilled - float mLevelMult = 0.0f; - float weapon_bonus = 0.0f; - if (IsInFeralForm()) - { - Unit::AuraEffectList const& mDummy = GetAuraEffectsByType(SPELL_AURA_DUMMY); - for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) - { - AuraEffect* aurEff = *itr; - if (aurEff->GetSpellInfo()->SpellIconID == 1563) - { - switch (aurEff->GetEffIndex()) - { - case 0: // Predatory Strikes (effect 0) - mLevelMult = CalculatePct(1.0f, aurEff->GetAmount()); - break; - case 1: // Predatory Strikes (effect 1) - if (Item* mainHand = m_items[EQUIPMENT_SLOT_MAINHAND]) - { - // also gains % attack power from equipped weapon - ItemTemplate const* proto = mainHand->GetTemplate(); - if (!proto) - continue; - - weapon_bonus = CalculatePct(float(proto->getFeralBonus()), aurEff->GetAmount()); - } - break; - default: - break; - } - } - } - } - - switch (GetShapeshiftForm()) - { - case FORM_CAT: - val2 = getLevel() * (mLevelMult + 2.0f) + GetStat(STAT_STRENGTH) * 2.0f + GetStat(STAT_AGILITY) - 20.0f + weapon_bonus + m_baseFeralAP; - break; - case FORM_BEAR: - case FORM_DIREBEAR: - val2 = getLevel() * (mLevelMult + 3.0f) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + weapon_bonus + m_baseFeralAP; - break; - case FORM_MOONKIN: - val2 = getLevel() * (mLevelMult + 1.5f) + GetStat(STAT_STRENGTH) * 2.0f - 20.0f + m_baseFeralAP; - break; - default: - val2 = GetStat(STAT_STRENGTH) * 2.0f - 20.0f; - break; - } - break; - } - case CLASS_MAGE: - val2 = GetStat(STAT_STRENGTH) - 10.0f; - break; - case CLASS_PRIEST: - val2 = GetStat(STAT_STRENGTH) - 10.0f; - break; - case CLASS_WARLOCK: - val2 = GetStat(STAT_STRENGTH) - 10.0f; - break; - } + float strengthValue = std::max((GetStat(STAT_STRENGTH) - 10.0f) * entry->APPerStrenth, 0.0f); + float agilityValue = std::max((GetStat(STAT_AGILITY) - 10.0f) * entry->APPerAgility, 0.0f); + + SpellShapeshiftFormEntry const* form = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm()); + // Directly taken from client, SHAPESHIFT_FLAG_AP_FROM_STRENGTH ? + if (form && form->flags1 & 0x20) + agilityValue += std::max((GetStat(STAT_AGILITY) - 10.0f) * entry->APPerStrenth, 0.0f); + + val2 = strengthValue + agilityValue; } SetModifierValue(unitMod, BASE_VALUE, val2); @@ -456,32 +339,15 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); //add dynamic flat mods - if (ranged) + if (!ranged) { - if ((getClassMask() & CLASSMASK_WAND_USERS) == 0) - { - AuraEffectList const& mRAPbyStat = GetAuraEffectsByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT); - for (AuraEffectList::const_iterator i = mRAPbyStat.begin(); i != mRAPbyStat.end(); ++i) - attPowerMod += CalculatePct(GetStat(Stats((*i)->GetMiscValue())), (*i)->GetAmount()); - } - } - else - { - AuraEffectList const& mAPbyStat = GetAuraEffectsByType(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT); - for (AuraEffectList::const_iterator i = mAPbyStat.begin(); i != mAPbyStat.end(); ++i) - attPowerMod += CalculatePct(GetStat(Stats((*i)->GetMiscValue())), (*i)->GetAmount()); - AuraEffectList const& mAPbyArmor = GetAuraEffectsByType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR); for (AuraEffectList::const_iterator iter = mAPbyArmor.begin(); iter != mAPbyArmor.end(); ++iter) // always: ((*i)->GetModifier()->m_miscvalue == 1 == SPELL_SCHOOL_MASK_NORMAL) attPowerMod += int32(GetArmor() / (*iter)->GetAmount()); } - float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; - SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field - SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field - SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field Pet* pet = GetPet(); //update pet's AP Guardian* guardian = GetGuardianPet(); @@ -508,11 +374,6 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) } } -void Player::UpdateShieldBlockValue() -{ - SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue()); -} - void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) { UnitMods unitMod; @@ -543,12 +404,20 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo if (IsInFeralForm()) // check if player is druid and in cat or bear forms { - uint8 lvl = getLevel(); - if (lvl > 60) - lvl = 60; + float weaponSpeed = BASE_ATTACK_TIME / 1000.f; + if (Item* weapon = GetWeaponForAttack(BASE_ATTACK, true)) + weaponSpeed = weapon->GetTemplate()->Delay / 1000; - weaponMinDamage = lvl * 0.85f * attackSpeedMod; - weaponMaxDamage = lvl * 1.25f * attackSpeedMod; + if (GetShapeshiftForm() == FORM_CAT) + { + weaponMinDamage = weaponMinDamage / weaponSpeed; + weaponMaxDamage = weaponMaxDamage / weaponSpeed; + } + else if (GetShapeshiftForm() == FORM_BEAR) + { + weaponMinDamage = weaponMinDamage / weaponSpeed + weaponMinDamage / 2.5; + weaponMaxDamage = weaponMinDamage / weaponSpeed + weaponMaxDamage / 2.5; + } } else if (!CanUseAttackType(attType)) // check if player not in form but still can't use (disarm case) { @@ -562,23 +431,18 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo weaponMinDamage = BASE_MINDAMAGE; weaponMaxDamage = BASE_MAXDAMAGE; } + /* + TODO: Is this still needed after ammo has been removed? else if (attType == RANGED_ATTACK) // add ammo DPS to ranged damage { weaponMinDamage += GetAmmoDPS() * attackSpeedMod; weaponMaxDamage += GetAmmoDPS() * attackSpeedMod; - } + }*/ minDamage = ((weaponMinDamage + baseValue) * basePct + totalValue) * totalPct; maxDamage = ((weaponMaxDamage + baseValue) * basePct + totalValue) * totalPct; } -void Player::UpdateDefenseBonusesMod() -{ - UpdateBlockPercentage(); - UpdateParryPercentage(); - UpdateDodgePercentage(); -} - void Player::UpdateBlockPercentage() { // No block @@ -587,8 +451,6 @@ void Player::UpdateBlockPercentage() { // Base value value = 5.0f; - // Modify value from defense skill - value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); // Increase from rating @@ -630,7 +492,7 @@ void Player::UpdateCritPercentage(WeaponAttackType attType) float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr); // Modify crit from weapon skill and maximized defense skill of same level victim difference - value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f; + value += (int32(GetMaxSkillValueForLevel()) - int32(GetMaxSkillValueForLevel())) * 0.04f; if (sWorld->getBoolConfig(CONFIG_STATS_LIMITS_ENABLE)) value = value > sWorld->getFloatConfig(CONFIG_STATS_LIMITS_CRIT) ? sWorld->getFloatConfig(CONFIG_STATS_LIMITS_CRIT) : value; @@ -652,6 +514,44 @@ void Player::UpdateAllCritPercentages() UpdateCritPercentage(RANGED_ATTACK); } +void Player::UpdateMastery() +{ + if (!CanUseMastery()) + { + SetFloatValue(PLAYER_MASTERY, 0.0f); + return; + } + + float value = GetTotalAuraModifier(SPELL_AURA_MASTERY); + value += GetRatingBonusValue(CR_MASTERY); + SetFloatValue(PLAYER_MASTERY, value); + + TalentTabEntry const* talentTab = sTalentTabStore.LookupEntry(GetPrimaryTalentTree(GetActiveSpec())); + if (!talentTab) + return; + + for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) + { + if (!talentTab->MasterySpellId[i]) + continue; + + if (Aura* aura = GetAura(talentTab->MasterySpellId[i])) + { + for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + { + if (!aura->HasEffect(j)) + continue; + + float mult = aura->GetSpellInfo()->Effects[j].BonusMultiplier; + if (G3D::fuzzyEq(mult, 0.0f)) + continue; + + aura->GetEffect(j)->ChangeAmount(int32(value * aura->GetSpellInfo()->Effects[j].BonusMultiplier)); + } + } + } +} + const float m_diminishing_k[MAX_CLASSES] = { 0.9560f, // Warrior @@ -667,43 +567,16 @@ const float m_diminishing_k[MAX_CLASSES] = 0.9720f // Druid }; -float Player::GetMissPercentageFromDefence() const -{ - float const miss_cap[MAX_CLASSES] = - { - 16.00f, // Warrior //correct - 16.00f, // Paladin //correct - 16.00f, // Hunter //? - 16.00f, // Rogue //? - 16.00f, // Priest //? - 16.00f, // DK //correct - 16.00f, // Shaman //? - 16.00f, // Mage //? - 16.00f, // Warlock //? - 0.0f, // ?? - 16.00f // Druid //? - }; - - float diminishing = 0.0f, nondiminishing = 0.0f; - // Modify value from defense skill (only bonus from defense rating diminishes) - nondiminishing += (GetSkillValue(SKILL_DEFENSE) - GetMaxSkillValueForLevel()) * 0.04f; - diminishing += (int32(GetRatingBonusValue(CR_DEFENSE_SKILL))) * 0.04f; - - // apply diminishing formula to diminishing miss chance - uint32 pclass = getClass()-1; - return nondiminishing + (diminishing * miss_cap[pclass] / (diminishing + miss_cap[pclass] * m_diminishing_k[pclass])); -} - void Player::UpdateParryPercentage() { const float parry_cap[MAX_CLASSES] = { - 47.003525f, // Warrior - 47.003525f, // Paladin + 65.631440f, // Warrior + 65.631440f, // Paladin 145.560408f, // Hunter 145.560408f, // Rogue 0.0f, // Priest - 47.003525f, // DK + 65.631440f, // DK 145.560408f, // Shaman 0.0f, // Mage 0.0f, // Warlock @@ -719,9 +592,6 @@ void Player::UpdateParryPercentage() float nondiminishing = 5.0f; // Parry from rating float diminishing = GetRatingBonusValue(CR_PARRY); - // Modify value from defense skill (only bonus from defense rating diminishes) - nondiminishing += (GetSkillValue(SKILL_DEFENSE) - GetMaxSkillValueForLevel()) * 0.04f; - diminishing += (int32(GetRatingBonusValue(CR_DEFENSE_SKILL))) * 0.04f; // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura nondiminishing += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); // apply diminishing formula to diminishing parry chance @@ -739,12 +609,12 @@ void Player::UpdateDodgePercentage() { const float dodge_cap[MAX_CLASSES] = { - 88.129021f, // Warrior - 88.129021f, // Paladin + 65.631440f, // Warrior + 65.631440f, // Paladin 145.560408f, // Hunter 145.560408f, // Rogue 150.375940f, // Priest - 88.129021f, // DK + 65.631440f, // DK 145.560408f, // Shaman 150.375940f, // Mage 150.375940f, // Warlock @@ -754,9 +624,6 @@ void Player::UpdateDodgePercentage() float diminishing = 0.0f, nondiminishing = 0.0f; GetDodgeFromAgility(diminishing, nondiminishing); - // Modify value from defense skill (only bonus from defense rating diminishes) - nondiminishing += (GetSkillValue(SKILL_DEFENSE) - GetMaxSkillValueForLevel()) * 0.04f; - diminishing += (int32(GetRatingBonusValue(CR_DEFENSE_SKILL))) * 0.04f; // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura nondiminishing += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); // Dodge from rating @@ -876,29 +743,23 @@ void Player::ApplyHealthRegenBonus(int32 amount, bool apply) void Player::UpdateManaRegen() { - float Intellect = GetStat(STAT_INTELLECT); - // Mana regen from spirit and intellect - float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit(); + // Mana regen from spirit + float spirit_regen = OCTRegenMPPerSpirit(); // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen - power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA); + spirit_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA); - // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura - float power_regen_mp5 = (GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) + m_baseManaRegen) / 5.0f; + // SpiritRegen(SPI, INT, LEVEL) = (0.001 + (SPI x sqrt(INT) x BASE_REGEN[LEVEL])) x 5 + if (GetStat(STAT_INTELLECT) > 0.0f) + spirit_regen *= sqrt(GetStat(STAT_INTELLECT)); - // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura - AuraEffectList const& regenAura = GetAuraEffectsByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT); - for (AuraEffectList::const_iterator i = regenAura.begin(); i != regenAura.end(); ++i) - { - power_regen_mp5 += GetStat(Stats((*i)->GetMiscValue())) * (*i)->GetAmount() / 500.0f; - } + // CombatRegen = 5% of Base Mana + float base_regen = GetCreateMana() * 0.01f + GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f; // Set regen rate in cast state apply only on spirit based regen int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT); - if (modManaRegenInterrupt > 100) - modManaRegenInterrupt = 100; - SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, power_regen_mp5 + CalculatePct(power_regen, modManaRegenInterrupt)); - SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, power_regen_mp5 + power_regen); + SetStatFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, base_regen + CalculatePct(spirit_regen, modManaRegenInterrupt)); + SetStatFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, 0.001f + spirit_regen + base_regen); } void Player::UpdateRuneRegen(RuneType rune) @@ -922,6 +783,13 @@ void Player::UpdateRuneRegen(RuneType rune) SetFloatValue(PLAYER_RUNE_REGEN_1 + uint8(rune), regen); } +void Player::UpdateAllRunesRegen() +{ + for (uint8 i = 0; i < NUM_RUNE_TYPES; ++i) + if (uint32 cooldown = GetRuneTypeBaseCooldown(RuneType(i))) + SetFloatValue(PLAYER_RUNE_REGEN_1 + i, float(1 * IN_MILLISECONDS) / float(cooldown)); +} + void Player::_ApplyAllStatBonuses() { SetCanModifyStats(false); @@ -1007,22 +875,18 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; uint16 index = UNIT_FIELD_ATTACK_POWER; - uint16 indexMod = UNIT_FIELD_ATTACK_POWER_MODS; uint16 indexMulti = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; if (ranged) { index = UNIT_FIELD_RANGED_ATTACK_POWER; - indexMod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS; indexMulti = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; } float baseAttackPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attackPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); float attackPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; SetInt32Value(index, uint32(baseAttackPower)); // UNIT_FIELD_(RANGED)_ATTACK_POWER - SetInt32Value(indexMod, uint32(attackPowerMod)); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS SetFloatValue(indexMulti, attackPowerMultiplier); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER // automatically update weapon damage after attack power modification @@ -1122,7 +986,7 @@ bool Guardian::UpdateStats(Stats stat) if (aurEff) { SpellInfo const* spellInfo = aurEff->GetSpellInfo(); // Then get the SpellProto and add the dummy effect value - AddPct(mod, spellInfo->Effects[EFFECT_1].CalcValue()); // Ravenous Dead edits the original scale + AddPct(mod, spellInfo->Effects[EFFECT_1].CalcValue(owner)); // Ravenous Dead edits the original scale } // Glyph of the Ghoul aurEff = owner->GetAuraEffect(58686, 0); @@ -1133,29 +997,8 @@ bool Guardian::UpdateStats(Stats stat) } else if (stat == STAT_STAMINA) { - if (owner->getClass() == CLASS_WARLOCK && IsPet()) - { - ownersBonus = CalculatePct(owner->GetStat(STAT_STAMINA), 75); - value += ownersBonus; - } - else - { - mod = 0.45f; - if (IsPet()) - { - PetSpellMap::const_iterator itr = (ToPet()->m_spells.find(62758)); // Wild Hunt rank 1 - if (itr == ToPet()->m_spells.end()) - itr = ToPet()->m_spells.find(62762); // Wild Hunt rank 2 - - if (itr != ToPet()->m_spells.end()) // If pet has Wild Hunt - { - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value - AddPct(mod, spellInfo->Effects[EFFECT_0].CalcValue()); - } - } - ownersBonus = float(owner->GetStat(stat)) * mod; - value += ownersBonus; - } + ownersBonus = CalculatePct(owner->GetStat(STAT_STAMINA), 30); + value += ownersBonus; } //warlock's and mage's pets gain 30% of owner's intellect else if (stat == STAT_INTELLECT) @@ -1227,13 +1070,14 @@ void Guardian::UpdateArmor() float bonus_armor = 0.0f; UnitMods unitMod = UNIT_MOD_ARMOR; - // hunter and warlock pets gain 35% of owner's armor value - if (IsPet()) - bonus_armor = float(CalculatePct(m_owner->GetArmor(), 35)); + // hunter pets gain 35% of owner's armor value, warlock pets gain 100% of owner's armor + if (IsHunterPet()) + bonus_armor = float(CalculatePct(m_owner->GetArmor(), 70)); + else if (IsPet()) + bonus_armor = m_owner->GetArmor(); value = GetModifierValue(unitMod, BASE_VALUE); value *= GetModifierValue(unitMod, BASE_PCT); - value += GetStat(STAT_AGILITY) * 2.0f; value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor; value *= GetModifierValue(unitMod, TOTAL_PCT); @@ -1310,19 +1154,6 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) if (IsHunterPet()) //hunter pets benefit from owner's attack power { float mod = 1.0f; //Hunter contribution modifier - if (IsPet()) - { - PetSpellMap::const_iterator itr = ToPet()->m_spells.find(62758); //Wild Hunt rank 1 - if (itr == ToPet()->m_spells.end()) - itr = ToPet()->m_spells.find(62762); //Wild Hunt rank 2 - - if (itr != ToPet()->m_spells.end()) // If pet has Wild Hunt - { - SpellInfo const* sProto = sSpellMgr->EnsureSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value - mod += CalculatePct(1.0f, sProto->Effects[1].CalcValue()); - } - } - bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f * mod; SetBonusDamage(int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f * mod)); } @@ -1342,8 +1173,8 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) //demons benefit from warlocks shadow or fire damage else if (IsPet()) { - int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); - int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW); + int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) + owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); + int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) + owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW); int32 maximum = (fire > shadow) ? fire : shadow; if (maximum < 0) maximum = 0; @@ -1353,7 +1184,7 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) //water elementals benefit from mage's frost damage else if (GetEntry() == ENTRY_WATER_ELEMENTAL) { - int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST); + int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) + owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST); if (frost < 0) frost = 0; SetBonusDamage(int32(frost * 0.4f)); @@ -1364,13 +1195,10 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); - float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; //UNIT_FIELD_(RANGED)_ATTACK_POWER field SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower); - //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field - SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier); @@ -1389,14 +1217,14 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType) //force of nature if (GetEntry() == ENTRY_TREANT) { - int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_NATURE)) - m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_NATURE); + int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_NATURE)) + m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_NATURE); if (spellDmg > 0) bonusDamage = spellDmg * 0.09f; } //greater fire elemental else if (GetEntry() == ENTRY_FIRE_ELEMENTAL) { - int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); + int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) + m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); if (spellDmg > 0) bonusDamage = spellDmg * 0.4f; } @@ -1417,27 +1245,6 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType) float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct; float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct; - // Pet's base damage changes depending on happiness - if (IsHunterPet() && attType == BASE_ATTACK) - { - switch (ToPet()->GetHappinessState()) - { - case HAPPY: - // 125% of normal damage - mindamage = mindamage * 1.25f; - maxdamage = maxdamage * 1.25f; - break; - case CONTENT: - // 100% of normal damage, nothing to modify - break; - case UNHAPPY: - // 75% of normal damage - mindamage = mindamage * 0.75f; - maxdamage = maxdamage * 0.75f; - break; - } - } - /// @todo: remove this Unit::AuraEffectList const& mDummy = GetAuraEffectsByType(SPELL_AURA_MOD_ATTACKSPEED); for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index f5b72b845a5..f096170c46d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -36,7 +36,6 @@ #include "Log.h" #include "MapManager.h" #include "MoveSpline.h" -#include "MoveSplineInit.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -60,6 +59,7 @@ #include "Vehicle.h" #include "World.h" #include "WorldPacket.h" +#include "MovementStructures.h" #include "WorldSession.h" #include <math.h> @@ -168,7 +168,7 @@ Unit::Unit(bool isWorldObject) : m_objectType |= TYPEMASK_UNIT; m_objectTypeId = TYPEID_UNIT; - m_updateFlag = (UPDATEFLAG_LIVING | UPDATEFLAG_STATIONARY_POSITION); + m_updateFlag = UPDATEFLAG_LIVING; m_attackTimer[BASE_ATTACK] = 0; m_attackTimer[OFF_ATTACK] = 0; @@ -180,7 +180,7 @@ Unit::Unit(bool isWorldObject) : m_extraAttacks = 0; m_canDualWield = false; - m_rootTimes = 0; + m_movementCounter = 0; m_state = 0; m_deathState = ALIVE; @@ -229,7 +229,6 @@ Unit::Unit(bool isWorldObject) : m_baseSpellCritChance = 5; m_CombatTimer = 0; - m_lastManaUse = 0; for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i) m_threatModifier[i] = 1.0f; @@ -406,7 +405,7 @@ void Unit::UpdateSplinePosition() pos.m_positionX = loc.x; pos.m_positionY = loc.y; pos.m_positionZ = loc.z; - pos.m_orientation = loc.orientation; + pos.SetOrientation(loc.orientation); if (TransportBase* transport = GetDirectTransport()) transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation); @@ -420,7 +419,7 @@ void Unit::UpdateSplinePosition() void Unit::DisableSpline() { - m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD)); + m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FORWARD); movespline->_Interrupt(); } @@ -437,7 +436,7 @@ float Unit::GetMeleeReach() const bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const { - if (!obj || !IsInMap(obj) || !InSamePhase(obj)) + if (!obj || !IsInMap(obj) || !IsInPhase(obj)) return false; float dx = GetPositionX() - obj->GetPositionX(); @@ -453,7 +452,7 @@ bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const bool Unit::IsWithinMeleeRange(const Unit* obj, float dist) const { - if (!obj || !IsInMap(obj) || !InSamePhase(obj)) + if (!obj || !IsInMap(obj) || !IsInPhase(obj)) return false; float dx = GetPositionX() - obj->GetPositionX(); @@ -623,32 +622,13 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam // Rage from Damage made (only from direct weapon damage) if (cleanDamage && damagetype == DIRECT_DAMAGE && this != victim && getPowerType() == POWER_RAGE) { - uint32 weaponSpeedHitFactor; - uint32 rage_damage = damage + cleanDamage->absorbed_damage; - + uint32 rage = uint32(GetAttackTime(cleanDamage->attackType) / 1000 * 8.125f); switch (cleanDamage->attackType) { - case BASE_ATTACK: - { - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 3.5f); - if (cleanDamage->hitOutCome == MELEE_HIT_CRIT) - weaponSpeedHitFactor *= 2; - - RewardRage(rage_damage, weaponSpeedHitFactor, true); - - break; - } case OFF_ATTACK: - { - weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * 1.75f); - if (cleanDamage->hitOutCome == MELEE_HIT_CRIT) - weaponSpeedHitFactor *= 2; - - RewardRage(rage_damage, weaponSpeedHitFactor, true); - - break; - } - case RANGED_ATTACK: + rage /= 2; + case BASE_ATTACK: + RewardRage(rage, true); break; default: break; @@ -659,7 +639,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam { // Rage from absorbed damage if (cleanDamage && cleanDamage->absorbed_damage && victim->getPowerType() == POWER_RAGE) - victim->RewardRage(cleanDamage->absorbed_damage, 0, false); + victim->RewardRage(cleanDamage->absorbed_damage, false); return 0; } @@ -704,7 +684,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam if (Battleground* bg = killer->GetBattleground()) bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage); - killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, victim); + killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, 0, victim); killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage); } @@ -760,7 +740,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam if (this != victim && victim->getPowerType() == POWER_RAGE) { uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0); - victim->RewardRage(rage_damage, 0, false); + victim->RewardRage(rage_damage, false); } if (GetTypeId() == TYPEID_PLAYER) @@ -977,7 +957,6 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama return; SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask); - uint32 crTypeMask = victim->GetCreatureTypeMask(); // Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage. if (!(spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) @@ -1021,9 +1000,6 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS critPctDamageMod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellInfo->GetSchoolMask()) - 1.0f) * 100; - // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS - critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask); - if (critPctDamageMod != 0) AddPct(damage, critPctDamageMod); } @@ -1031,22 +1007,18 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama // Spell weapon based damage CAN BE crit & blocked at same time if (blocked) { - damageInfo->blocked = victim->GetShieldBlockValue(); // double blocked amount if block is critical + uint32 value = victim->GetBlockPercent(); if (victim->isBlockCritical()) - damageInfo->blocked += damageInfo->blocked; - if (damage < int32(damageInfo->blocked)) - damageInfo->blocked = uint32(damage); + value *= 2; // double blocked percent + damageInfo->blocked = CalculatePct(damage, value); damage -= damageInfo->blocked; } - if (attackType != RANGED_ATTACK) - ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_MELEE); - else - ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_RANGED); + ApplyResilience(victim, &damage); break; } - // Magical Attacks + // Magical Attacks case SPELL_DAMAGE_CLASS_NONE: case SPELL_DAMAGE_CLASS_MAGIC: { @@ -1055,10 +1027,12 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama { damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; damage = SpellCriticalDamageBonus(spellInfo, damage, victim); + } - ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_SPELL); + ApplyResilience(victim, &damage); break; + } default: break; @@ -1216,10 +1190,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, damageInfo->damageSchoolMask) - 1.0f) * 100; - uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask(); - - // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS - mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask); if (mod != 0) AddPct(damageInfo->damage, mod); break; @@ -1239,19 +1209,9 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam case MELEE_HIT_BLOCK: damageInfo->TargetState = VICTIMSTATE_HIT; damageInfo->HitInfo |= HITINFO_BLOCK; - damageInfo->procEx |= PROC_EX_BLOCK; - damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue(); - // double blocked amount if block is critical - if (damageInfo->target->isBlockCritical()) - damageInfo->blocked_amount+=damageInfo->blocked_amount; - if (damageInfo->blocked_amount >= damageInfo->damage) - { - damageInfo->TargetState = VICTIMSTATE_BLOCKS; - damageInfo->blocked_amount = damageInfo->damage; - damageInfo->procEx |= PROC_EX_FULL_BLOCK; - } - else - damageInfo->procEx |= PROC_EX_NORMAL_HIT; + damageInfo->procEx |= PROC_EX_BLOCK | PROC_EX_NORMAL_HIT; + // 30% damage blocked, double blocked amount if block is critical + damageInfo->blocked_amount = CalculatePct(damageInfo->damage, damageInfo->target->isBlockCritical() ? damageInfo->target->GetBlockPercent() * 2 : damageInfo->target->GetBlockPercent()); damageInfo->damage -= damageInfo->blocked_amount; damageInfo->cleanDamage += damageInfo->blocked_amount; break; @@ -1284,8 +1244,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM; int32 resilienceReduction = damageInfo->damage; - // attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here - ApplyResilience(victim, NULL, &resilienceReduction, (damageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE); + ApplyResilience(victim, &resilienceReduction); resilienceReduction = damageInfo->damage - resilienceReduction; damageInfo->damage -= resilienceReduction; damageInfo->cleanDamage += resilienceReduction; @@ -1374,8 +1333,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) if (victim->getLevel() < 30) Probability = 0.65f * victim->getLevel() + 0.5f; - uint32 VictimDefense=victim->GetDefenseSkillValue(); - uint32 AttackerMeleeSkill=GetUnitMeleeSkill(); + uint32 VictimDefense = victim->GetMaxSkillValueForLevel(this); + uint32 AttackerMeleeSkill = GetMaxSkillValueForLevel(); Probability *= AttackerMeleeSkill/(float)VictimDefense*0.16; @@ -1435,6 +1394,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) int32 overkill = int32(damage) - int32(GetHealth()); data << uint32(overkill > 0 ? overkill : 0); // Overkill data << uint32(i_spellProto->SchoolMask); + data << uint32(0); // FIX ME: Send resisted damage, both fully resisted and partly resisted victim->SendMessageToSet(&data, true); victim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, i_spellProto->GetSchoolMask(), i_spellProto, true); @@ -1477,6 +1437,14 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo { float armor = float(victim->GetArmor()); + // bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER + int32 armorBypassPct = 0; + AuraEffectList const & reductionAuras = victim->GetAuraEffectsByType(SPELL_AURA_BYPASS_ARMOR_FOR_CASTER); + for (AuraEffectList::const_iterator i = reductionAuras.begin(); i != reductionAuras.end(); ++i) + if ((*i)->GetCasterGUID() == GetGUID()) + armorBypassPct += (*i)->GetAmount(); + armor = CalculatePct(armor, 100 - std::min(armorBypassPct, 100)); + // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); @@ -1484,14 +1452,6 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor); - AuraEffectList const& resIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST); - for (AuraEffectList::const_iterator j = resIgnoreAurasAb.begin(); j != resIgnoreAurasAb.end(); ++j) - { - if ((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL - && (*j)->IsAffectedOnSpell(spellInfo)) - armor = floor(AddPct(armor, -(*j)->GetAmount())); - } - AuraEffectList const& resIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST); for (AuraEffectList::const_iterator j = resIgnoreAuras.begin(); j != resIgnoreAuras.end(); ++j) { @@ -1499,27 +1459,9 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo armor = floor(AddPct(armor, -(*j)->GetAmount())); } - // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc. + // Apply Player CR_ARMOR_PENETRATION rating if (GetTypeId() == TYPEID_PLAYER) { - float bonusPct = 0; - AuraEffectList const& armorPenAuras = GetAuraEffectsByType(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT); - for (AuraEffectList::const_iterator itr = armorPenAuras.begin(); itr != armorPenAuras.end(); ++itr) - { - if ((*itr)->GetSpellInfo()->EquippedItemClass == -1) - { - if (!spellInfo || (*itr)->IsAffectedOnSpell(spellInfo) || (*itr)->GetMiscValue() & spellInfo->GetSchoolMask()) - bonusPct += (*itr)->GetAmount(); - else if (!(*itr)->GetMiscValue() && !(*itr)->HasSpellClassMask()) - bonusPct += (*itr)->GetAmount(); - } - else - { - if (ToPlayer()->HasItemFitToSpellRequirements((*itr)->GetSpellInfo())) - bonusPct += (*itr)->GetAmount(); - } - } - float maxArmorPen = 0; if (victim->getLevel() < 60) maxArmorPen = float(400 + 85 * victim->getLevel()); @@ -1529,7 +1471,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo // Cap armor penetration to this number maxArmorPen = std::min((armor + maxArmorPen) / 3, armor); // Figure out how much armor do we ignore - float armorPen = CalculatePct(maxArmorPen, bonusPct + ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION)); + float armorPen = CalculatePct(maxArmorPen, ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION)); // Got the value, apply it armor -= std::min(armorPen, maxArmorPen); } @@ -1562,13 +1504,13 @@ uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, Spell if (spellInfo && spellInfo->AttributesEx4 & SPELL_ATTR4_IGNORE_RESISTANCES) return 0; - uint32 const BOSS_LEVEL = 83; - uint32 const BOSS_RESISTANCE_CONSTANT = 510; + uint8 const bossLevel = 83; + uint32 const bossResistanceConstant = 510; uint32 resistanceConstant = 0; uint8 level = victim->getLevel(); - if (level == BOSS_LEVEL) - resistanceConstant = BOSS_RESISTANCE_CONSTANT; + if (level == bossLevel) + resistanceConstant = bossResistanceConstant; else resistanceConstant = level * 5; @@ -1585,11 +1527,6 @@ uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, Spell { int32 ignoredResistance = 0; - AuraEffectList const& ResIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST); - for (AuraEffectList::const_iterator itr = ResIgnoreAurasAb.begin(); itr != ResIgnoreAurasAb.end(); ++itr) - if (((*itr)->GetMiscValue() & schoolMask) && (*itr)->IsAffectedOnSpell(spellInfo)) - ignoredResistance += (*itr)->GetAmount(); - AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST); for (AuraEffectList::const_iterator itr = ResIgnoreAuras.begin(); itr != ResIgnoreAuras.end(); ++itr) if ((*itr)->GetMiscValue() & schoolMask) @@ -1657,7 +1594,7 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe if (!((*itr)->GetMiscValue() & schoolMask)) continue; - if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo)) + if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectingSpell(spellInfo)) auraAbsorbMod = float((*itr)->GetAmount()); } @@ -1781,40 +1718,6 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe { // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation - AuraEffectList vSplitDamageFlatCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT)); - for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr) - { - // Check if aura was removed during iteration - we don't need to work on such auras - if (!((*itr)->GetBase()->IsAppliedOnTarget(victim->GetGUID()))) - continue; - // check damage school mask - if (!((*itr)->GetMiscValue() & schoolMask)) - continue; - - // Damage can be splitted only if aura has an alive caster - Unit* caster = (*itr)->GetCaster(); - if (!caster || (caster == victim) || !caster->IsInWorld() || !caster->IsAlive()) - continue; - - int32 splitDamage = (*itr)->GetAmount(); - - // absorb must be smaller than the damage itself - splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage())); - - dmgInfo.AbsorbDamage(splitDamage); - - uint32 splitted = splitDamage; - uint32 splitted_absorb = 0; - DealDamageMods(caster, splitted, &splitted_absorb); - - SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false); - - CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellInfo(), false); - } - - // We're going to call functions which can modify content of the list during iteration over it's elements - // Let's copy the list so we can prevent iterator invalidation AuraEffectList vSplitDamagePctCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT)); for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && dmgInfo.GetDamage() > 0; ++itr) { @@ -1978,7 +1881,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackTy // Miss chance based on melee //float miss_chance = MeleeMissChanceCalc(victim, attType); - float miss_chance = MeleeSpellMissChance(victim, attType, int32(GetWeaponSkillValue(attType, victim)) - int32(GetMaxSkillValueForLevel(this)), 0); + float miss_chance = MeleeSpellMissChance(victim, attType, 0); // Critical hit chance float crit_chance = GetUnitCriticalChance(attType, victim); @@ -2002,11 +1905,8 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim); int32 victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this); - int32 attackerWeaponSkill = GetWeaponSkillValue(attType, victim); - int32 victimDefenseSkill = victim->GetDefenseSkillValue(this); - // bonus from skills is 0.04% - int32 skillBonus = 4 * (attackerWeaponSkill - victimMaxSkillValueForLevel); + int32 skillBonus = 4 * (attackerMaxSkillValueForLevel - victimMaxSkillValueForLevel); int32 sum = 0, tmp = 0; int32 roll = urand (0, 10000); @@ -2115,11 +2015,9 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT getLevel() < victim->getLevelForTarget(this)) { // cap possible value (with bonuses > max skill) - int32 skill = attackerWeaponSkill; - int32 maxskill = attackerMaxSkillValueForLevel; - skill = (skill > maxskill) ? maxskill : skill; + int32 skill = attackerMaxSkillValueForLevel; - tmp = (10 + (victimDefenseSkill - skill)) * 100; + tmp = (10 + (victimMaxSkillValueForLevel - skill)) * 100; tmp = tmp > 4000 ? 4000 : tmp; if (roll < (sum += tmp)) { @@ -2135,10 +2033,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT !(GetTypeId() == TYPEID_UNIT && ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH)) { // when their weapon skill is 15 or more above victim's defense skill - tmp = victimDefenseSkill; - int32 tmpmax = victimMaxSkillValueForLevel; - // having defense above your maximum (from items, talents etc.) has no effect - tmp = tmp > tmpmax ? tmpmax : tmp; + tmp = victimMaxSkillValueForLevel; // tmp = mob's level * 5 - player's current defense skill tmp = attackerMaxSkillValueForLevel - tmp; if (tmp >= 15) @@ -2238,7 +2133,7 @@ void Unit::SendMeleeAttackStop(Unit* victim) TC_LOG_INFO("entities.unit", "%s %u stopped attacking", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow()); } -bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType) +bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType /*attackType*/) { // These spells can't be blocked if (spellProto && spellProto->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK) @@ -2251,9 +2146,7 @@ bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttac victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK) return false; - float blockChance = victim->GetUnitBlockChance(); - blockChance += (int32(GetWeaponSkillValue(attackType)) - int32(victim->GetMaxSkillValueForLevel())) * 0.04f; - if (roll_chance_f(blockChance)) + if (roll_chance_f(victim->GetUnitBlockChance())) return true; } return false; @@ -2318,19 +2211,10 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED) attType = RANGED_ATTACK; - int32 attackerWeaponSkill; - // skill value for these spells (for example judgements) is 5* level - if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !spellInfo->IsRangedWeaponSpell()) - attackerWeaponSkill = getLevel() * 5; - // bonus from skills is 0.04% per skill Diff - else - attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim)); - - int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this)); + uint32 roll = urand(0, 10000); - uint32 roll = urand (0, 10000); + uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, spellInfo->Id) * 100.0f); - uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, skillDiff, spellInfo->Id) * 100.0f); // Roll miss uint32 tmp = missChance; if (roll < tmp) @@ -2417,7 +2301,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo AuraEffectList const& ignore = GetAuraEffectsByType(SPELL_AURA_IGNORE_COMBAT_RESULT); for (AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) { - if (!(*i)->IsAffectedOnSpell(spellInfo)) + if (!(*i)->IsAffectingSpell(spellInfo)) continue; switch ((*i)->GetMiscValue()) { @@ -2439,7 +2323,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canDodge) { // Roll dodge - int32 dodgeChance = int32(victim->GetUnitDodgeChance() * 100.0f) - skillDiff * 4; + int32 dodgeChance = int32(victim->GetUnitDodgeChance() * 100.0f); // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE dodgeChance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100; dodgeChance = int32(float(dodgeChance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE)); @@ -2458,7 +2342,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canParry) { // Roll parry - int32 parryChance = int32(victim->GetUnitParryChance() * 100.0f) - skillDiff * 4; + int32 parryChance = int32(victim->GetUnitParryChance() * 100.0f); // Reduce parry chance by attacker expertise rating if (GetTypeId() == TYPEID_PLAYER) parryChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); @@ -2474,7 +2358,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (canBlock) { - int32 blockChance = int32(victim->GetUnitBlockChance() * 100.0f) - skillDiff * 4; + int32 blockChance = int32(victim->GetUnitBlockChance() * 100.0f); if (blockChance < 0) blockChance = 0; tmp += blockChance; @@ -2512,18 +2396,12 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); - // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras - modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask); - - // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras - modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask); - // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura - if (spellInfo->IsAffectingArea()) - modHitChance -= victim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE); - - // Decrease hit chance from victim rating bonus - if (victim->GetTypeId() == TYPEID_PLAYER) - modHitChance -= int32(victim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)); + // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects + if (!(spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)) + { + // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras + modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask); + } int32 HitChance = modHitChance * 100; // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings @@ -2542,26 +2420,6 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100; tmp += resist_chance; - // Chance resist debuff - if (!spellInfo->IsPositive()) - { - bool hasAura = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (spellInfo->Effects[i].IsAura()) - { - hasAura = true; - break; - } - } - - if (hasAura) - { - tmp += victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellInfo->Dispel)) * 100; - tmp += victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellInfo->Dispel)) * 100; - } - } - // Roll chance if (rand < tmp) return SPELL_MISS_RESIST; @@ -2637,41 +2495,11 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, boo return SPELL_MISS_NONE; } -uint32 Unit::GetShieldBlockValue(uint32 soft_cap, uint32 hard_cap) const -{ - uint32 value = GetShieldBlockValue(); - if (value >= hard_cap) - { - value = (soft_cap + hard_cap) / 2; - } - else if (value > soft_cap) - { - value = soft_cap + ((value - soft_cap) / 2); - } - - return value; -} - uint32 Unit::GetUnitMeleeSkill(Unit const* target) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } -uint32 Unit::GetDefenseSkillValue(Unit const* target) const -{ - if (GetTypeId() == TYPEID_PLAYER) - { - // in PvP use full skill instead current skill value - uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER) - ? ToPlayer()->GetMaxSkillValue(SKILL_DEFENSE) - : ToPlayer()->GetSkillValue(SKILL_DEFENSE); - value += uint32(ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL)); - return value; - } - else - return GetUnitMeleeSkill(target); -} - float Unit::GetUnitDodgeChance() const { if (IsNonMeleeSpellCast(false) || HasUnitState(UNIT_STATE_CONTROLLED)) @@ -2727,9 +2555,6 @@ float Unit::GetUnitMissChance(WeaponAttackType attType) const { float miss_chance = 5.00f; - if (Player const* player = ToPlayer()) - miss_chance += player->GetMissPercentageFromDefence(); - if (attType == RANGED_ATTACK) miss_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); else @@ -2748,7 +2573,7 @@ float Unit::GetUnitBlockChance() const if (player->CanBlock()) { Item* tmpitem = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->Block) + if (tmpitem && !tmpitem->IsBroken()) return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); } // is player but has no block ability or no not broken shield equipped @@ -2805,63 +2630,11 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victi crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); - // reduce crit chance from Rating for players - if (attackType != RANGED_ATTACK) - { - ApplyResilience(victim, &crit, NULL, false, CR_CRIT_TAKEN_MELEE); - // Glyph of barkskin - if (victim->HasAura(63057) && victim->HasAura(22812)) - crit -= 25.0f; - } - else - ApplyResilience(victim, &crit, NULL, false, CR_CRIT_TAKEN_RANGED); - - // Apply crit chance from defence skill - crit += (int32(GetMaxSkillValueForLevel(victim)) - int32(victim->GetDefenseSkillValue(this))) * 0.04f; - if (crit < 0.0f) crit = 0.0f; return crit; } -uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) const -{ - uint32 value = 0; - if (Player const* player = ToPlayer()) - { - Item* item = player->GetWeaponForAttack(attType, true); - - // feral or unarmed skill only for base attack - if (attType != BASE_ATTACK && !item) - return 0; - - if (IsInFeralForm()) - return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact - - // weapon skill or (unarmed for base attack) - uint32 skill = SKILL_UNARMED; - if (item) - skill = item->GetSkill(); - - // in PvP use full skill instead current skill value - value = (target && target->IsControlledByPlayer()) - ? player->GetMaxSkillValue(skill) - : player->GetSkillValue(skill); - // Modify value from ratings - value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL)); - switch (attType) - { - case BASE_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND)); break; - case OFF_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND)); break; - case RANGED_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED)); break; - default: break; - } - } - else - value = GetUnitMeleeSkill(target); - return value; -} - void Unit::_DeleteRemovedAuras() { while (!m_removedAuras.empty()) @@ -2930,7 +2703,9 @@ void Unit::_UpdateSpells(uint32 time) void Unit::_UpdateAutoRepeatSpell() { // check "realtime" interrupts - if ((GetTypeId() == TYPEID_PLAYER && ToPlayer()->isMoving()) || IsNonMeleeSpellCast(false, false, true, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == 75)) + // don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect + if (((GetTypeId() == TYPEID_PLAYER && ToPlayer()->isMoving()) || IsNonMeleeSpellCast(false, false, true, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == 75)) && + !HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo)) { // cancel wand shoot if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75) @@ -3873,7 +3648,7 @@ void Unit::RemoveAurasWithAttribute(uint32 flags) } } -void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase) +void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid) { // single target auras from other casters for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();) @@ -3883,12 +3658,12 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase) if (aura->GetCasterGUID() != GetGUID() && aura->GetSpellInfo()->IsSingleTarget()) { - if (!newPhase) + if (!newPhase && !phaseid) RemoveAura(iter); else { Unit* caster = aura->GetCaster(); - if (!caster || !caster->InSamePhase(newPhase)) + if (!caster || (newPhase && !caster->InSamePhase(newPhase)) || (!newPhase && !caster->IsInPhase(this))) RemoveAura(iter); else ++iter; @@ -3923,7 +3698,8 @@ void Unit::RemoveAurasWithInterruptFlags(uint32 flag, uint32 except) { Aura* aura = (*iter)->GetBase(); ++iter; - if ((aura->GetSpellInfo()->AuraInterruptFlags & flag) && (!except || aura->GetId() != except)) + if ((aura->GetSpellInfo()->AuraInterruptFlags & flag) && (!except || aura->GetId() != except) + && !(flag & AURA_INTERRUPT_FLAG_MOVE && HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, aura->GetSpellInfo()))) { uint32 removedAuras = m_removedAurasCount; RemoveAura(aura); @@ -3936,7 +3712,8 @@ void Unit::RemoveAurasWithInterruptFlags(uint32 flag, uint32 except) if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL]) if (spell->getState() == SPELL_STATE_CASTING && (spell->m_spellInfo->ChannelInterruptFlags & flag) - && spell->m_spellInfo->Id != except) + && spell->m_spellInfo->Id != except + && !(flag & AURA_INTERRUPT_FLAG_MOVE && HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, spell->GetSpellInfo()))) InterruptNonMeleeSpells(false); UpdateInterruptMask(); @@ -4373,7 +4150,7 @@ bool Unit::HasAuraTypeWithAffectMask(AuraType auratype, SpellInfo const* affecte { AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - if ((*i)->IsAffectedOnSpell(affectedSpell)) + if ((*i)->IsAffectingSpell(affectedSpell)) return true; return false; } @@ -4433,7 +4210,7 @@ AuraEffect* Unit::IsScriptOverriden(SpellInfo const* spell, int32 script) const for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i) { if ((*i)->GetMiscValue() == script) - if ((*i)->IsAffectedOnSpell(spell)) + if ((*i)->IsAffectingSpell(spell)) return (*i); } return NULL; @@ -4694,7 +4471,7 @@ int32 Unit::GetTotalAuraModifierByAffectMask(AuraType auratype, SpellInfo const* AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->IsAffectedOnSpell(affectedSpell)) + if ((*i)->IsAffectingSpell(affectedSpell)) if (!sSpellMgr->AddSameEffectStackRuleSpellGroups((*i)->GetSpellInfo(), (*i)->GetAmount(), SameEffectSpellGroup)) modifier += (*i)->GetAmount(); } @@ -4713,7 +4490,7 @@ float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auratype, SpellInfo cons AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->IsAffectedOnSpell(affectedSpell)) + if ((*i)->IsAffectingSpell(affectedSpell)) if (!sSpellMgr->AddSameEffectStackRuleSpellGroups((*i)->GetSpellInfo(), (*i)->GetAmount(), SameEffectSpellGroup)) AddPct(multiplier, (*i)->GetAmount()); } @@ -4731,7 +4508,7 @@ int32 Unit::GetMaxPositiveAuraModifierByAffectMask(AuraType auratype, SpellInfo AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->IsAffectedOnSpell(affectedSpell) && (*i)->GetAmount() > modifier) + if ((*i)->IsAffectingSpell(affectedSpell) && (*i)->GetAmount() > modifier) modifier = (*i)->GetAmount(); } @@ -4745,7 +4522,7 @@ int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellInfo AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->IsAffectedOnSpell(affectedSpell) && (*i)->GetAmount() < modifier) + if ((*i)->IsAffectingSpell(affectedSpell) && (*i)->GetAmount() < modifier) modifier = (*i)->GetAmount(); } @@ -5122,8 +4899,11 @@ void Unit::SendAttackStateUpdate(CalcDamageInfo* damageInfo) data << float(0); data << float(0); data << float(0); - data << float(0); // Found in a loop with 1 iteration - data << float(0); // ditto ^ + for (uint8 i = 0; i < 2; ++i) + { + data << float(0); + data << float(0); + } data << uint32(0); } @@ -5145,6 +4925,133 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType SendAttackStateUpdate(&dmgInfo); } +bool Unit::HandleAuraProcOnPowerAmount(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 /*procEx*/, uint32 cooldown) +{ + // Get triggered aura spell info + SpellInfo const* auraSpellInfo = triggeredByAura->GetSpellInfo(); + + // Get effect index used for the proc + uint32 effIndex = triggeredByAura->GetEffIndex(); + + // Power amount required to proc the spell + int32 powerAmountRequired = triggeredByAura->GetAmount(); + // Power type required to proc + Powers powerRequired = Powers(auraSpellInfo->Effects[triggeredByAura->GetEffIndex()].MiscValue); + + // Set trigger spell id, target, custom basepoints + uint32 trigger_spell_id = auraSpellInfo->Effects[triggeredByAura->GetEffIndex()].TriggerSpell; + + Unit* target = NULL; + int32 basepoints0 = 0; + + Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER + ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL; + + /* Try handle unknown trigger spells or with invalid power amount or misc value + if (sSpellMgr->GetSpellInfo(trigger_spell_id) == NULL || powerAmountRequired == NULL || powerRequired >= MAX_POWER) + { + switch (auraSpellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + break; + } + } + }*/ + + // All ok. Check current trigger spell + SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(trigger_spell_id); + if (triggerEntry == NULL) + { + // Not cast unknown spell + // TC_LOG_ERROR("Unit::HandleAuraProcOnPowerAmount: Spell %u have 0 in EffectTriggered[%d], not handled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex()); + return false; + } + + // not allow proc extra attack spell at extra attack + if (m_extraAttacks && triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + return false; + + if (!powerRequired || !powerAmountRequired) + { + TC_LOG_ERROR("spells", "Unit::HandleAuraProcOnPowerAmount: Spell %u have 0 powerAmountRequired in EffectAmount[%d] or 0 powerRequired in EffectMiscValue, not handled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex()); + return false; + } + + if (GetPower(powerRequired) != powerAmountRequired) + return false; + + // Custom requirements (not listed in procEx) Warning! damage dealing after this + // Custom triggered spells + switch (auraSpellInfo->SpellFamilyName) + { + case SPELLFAMILY_DRUID: + { + // Eclipse Mastery Driver Passive + if (auraSpellInfo->Id == 79577) + { + uint32 solarEclipseMarker = 67483; + uint32 lunarEclipseMarker = 67484; + + switch (effIndex) + { + case 0: + { + if (HasAura(trigger_spell_id)) + return false; + + // Do not proc if proc spell isnt starfire and starsurge + if (procSpell->Id != 2912 && procSpell->Id != 78674) + return false; + + if (HasAura(solarEclipseMarker)) + { + RemoveAurasDueToSpell(solarEclipseMarker); + CastSpell(this, lunarEclipseMarker, true); + } + break; + } + case 1: + { + if (HasAura(trigger_spell_id)) + return false; + + // Do not proc if proc spell isnt wrath and starsurge + if (procSpell->Id != 5176 && procSpell->Id != 78674) + return false; + + if (HasAura(lunarEclipseMarker)) + { + RemoveAurasDueToSpell(lunarEclipseMarker); + CastSpell(this, solarEclipseMarker, true); + } + + break; + } + } + } + break; + } + } + + if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id)) + return false; + + // try detect target manually if not set + if (target == NULL) + target = !(procFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)) && triggerEntry && triggerEntry->IsPositive() ? this : victim; + + if (basepoints0) + CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); + else + CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura); + + if (cooldown && GetTypeId() == TYPEID_PLAYER) + ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown); + + return true; +} + //victim may be NULL bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown) { @@ -5417,18 +5324,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere victim->RemoveAurasWithMechanic(1<<MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL); return true; } - // Glyph of Scourge Strike - case 58642: - { - triggered_spell_id = 69961; // Glyph of Scourge Strike - break; - } - // Glyph of Life Tap - case 63320: - { - triggered_spell_id = 63321; // Life Tap - break; - } // Purified Shard of the Scale - Onyxia 10 Caster Trinket case 69755: { @@ -5545,41 +5440,25 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere instance->DoCastSpellOnPlayers(65037); // Achievement criteria marker break; } + case 47020: // Enter vehicle XT-002 (Scrapbot) + { + if (GetTypeId() != TYPEID_UNIT) + return false; + + Unit* vehicleBase = GetVehicleBase(); + if (!vehicleBase) + return false; + + // Todo: Check if this amount is blizzlike + vehicleBase->ModifyHealth(int32(vehicleBase->CountPctFromMaxHealth(1))); + break; + } } break; } case SPELLFAMILY_MAGE: { - // Magic Absorption - if (dummySpell->SpellIconID == 459) // only this spell has SpellIconID == 459 and dummy aura - { - if (getPowerType() != POWER_MANA) - return false; - - // mana reward - basepoints0 = CalculatePct(int32(GetMaxPower(POWER_MANA)), triggerAmount); - target = this; - triggered_spell_id = 29442; - break; - } - // Arcane Potency - if (dummySpell->SpellIconID == 2120) - { - if (!procSpell) - return false; - - target = this; - switch (dummySpell->Id) - { - case 31571: triggered_spell_id = 57529; break; - case 31572: triggered_spell_id = 57531; break; - default: - TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled spell id: %u", dummySpell->Id); - return false; - } - break; - } - // Hot Streak + // Hot Streak & Improved Hot Streak if (dummySpell->SpellIconID == 2999) { if (effIndex != 0) @@ -5592,7 +5471,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (procEx & PROC_EX_CRITICAL_HIT) { counter->SetAmount(counter->GetAmount() * 2); - if (counter->GetAmount() < 100) // not enough + if (counter->GetAmount() < 100 && dummySpell->Id != 44445) // not enough or Hot Streak spell return true; // Crititcal counted -> roll chance if (roll_chance_i(triggerAmount)) @@ -5611,109 +5490,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 37436; break; } - switch (dummySpell->Id) - { - // Glyph of Polymorph - case 56375: - { - if (!target) - return false; - target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, 0, target->GetAura(32409)); // SW:D shall not be removed. - target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); - target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH); - return true; - } - // Glyph of Icy Veins - case 56374: - { - RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, 0, 0, true, false); - RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); - return true; - } - // Glyph of Ice Block - case 56372: - { - Player* player = ToPlayer(); - if (!player) - return false; - - SpellCooldowns const cooldowns = player->GetSpellCooldowns(); - // remove cooldowns on all ranks of Frost Nova - for (SpellCooldowns::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr) - { - SpellInfo const* cdSpell = sSpellMgr->GetSpellInfo(itr->first); - // Frost Nova - if (cdSpell && cdSpell->SpellFamilyName == SPELLFAMILY_MAGE - && cdSpell->SpellFamilyFlags[0] & 0x00000040) - player->RemoveSpellCooldown(cdSpell->Id, true); - } - break; - } - case 47020: // Enter vehicle XT-002 (Scrapbot) - { - if (GetTypeId() != TYPEID_UNIT) - return false; - - Unit* vehicleBase = GetVehicleBase(); - if (!vehicleBase) - return false; - - /// @todo Check if this amount is blizzlike - vehicleBase->ModifyHealth(int32(vehicleBase->CountPctFromMaxHealth(1))); - break; - } - } - break; - } - case SPELLFAMILY_WARRIOR: - { - switch (dummySpell->Id) - { - // Victorious - case 32216: - { - RemoveAura(dummySpell->Id); - return false; - } - // Improved Spell Reflection - case 59088: - case 59089: - { - triggered_spell_id = 59725; - target = this; - break; - } - } - // Second Wind - if (dummySpell->SpellIconID == 1697) - { - // only for spells and hit/crit (trigger start always) and not start from self cast spells (5530 Mace Stun Effect for example) - if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim) - return false; - // Need stun or root mechanic - if (!(procSpell->GetAllEffectsMechanicMask() & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_STUN)))) - return false; - - switch (dummySpell->Id) - { - case 29838: triggered_spell_id=29842; break; - case 29834: triggered_spell_id=29841; break; - case 42770: triggered_spell_id=42771; break; - default: - TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled spell id: %u (SW)", dummySpell->Id); - return false; - } - - target = this; - break; - } - // Glyph of Blocking - if (dummySpell->Id == 58375) - { - triggered_spell_id = 58374; - break; - } - break; } case SPELLFAMILY_WARLOCK: { @@ -5766,54 +5542,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } switch (dummySpell->Id) { - // Nightfall - case 18094: - case 18095: - // Glyph of corruption - case 56218: - { - target = this; - triggered_spell_id = 17941; - break; - } - // Soul Leech - case 30293: - case 30295: - case 30296: - { - // Improved Soul Leech - AuraEffectList const& SoulLeechAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY); - for (Unit::AuraEffectList::const_iterator i = SoulLeechAuras.begin(); i != SoulLeechAuras.end(); ++i) - { - if ((*i)->GetId() == 54117 || (*i)->GetId() == 54118) - { - if ((*i)->GetEffIndex() != 0) - continue; - basepoints0 = int32((*i)->GetAmount()); - target = GetGuardianPet(); - if (target) - { - // regen mana for pet - CastCustomSpell(target, 54607, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - } - // regen mana for caster - CastCustomSpell(this, 59117, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - // Get second aura of spell for replenishment effect on party - if (AuraEffect const* aurEff = (*i)->GetBase()->GetEffect(EFFECT_1)) - { - // Replenishment - roll chance - if (roll_chance_i(aurEff->GetAmount())) - CastSpell(this, 57669, true, castItem, triggeredByAura); - } - break; - } - } - // health - basepoints0 = CalculatePct(int32(damage), triggerAmount); - target = this; - triggered_spell_id = 30294; - break; - } // Shadowflame (Voidheart Raiment set bonus) case 37377: { @@ -5838,63 +5566,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 37378; break; } - // Glyph of Succubus - case 56250: - { - if (!target) - return false; - target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, 0, target->GetAura(32409)); // SW:D shall not be removed. - target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); - target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH); - return true; - } } break; } case SPELLFAMILY_PRIEST: { - // Vampiric Touch - if (dummySpell->SpellFamilyFlags[1] & 0x00000400) - { - if (!victim || !victim->IsAlive()) - return false; - - if (effIndex != 0) - return false; - - // victim is caster of aura - if (triggeredByAura->GetCasterGUID() != victim->GetGUID()) - return false; - - // Energize 0.25% of max. mana - victim->CastSpell(victim, 57669, true, castItem, triggeredByAura); - return true; // no hidden cooldown - } - // Body and Soul - if (dummySpell->SpellIconID == 2218) - { - // Proc only from Abolish desease on self cast - if (procSpell->Id != 552 || victim != this || !roll_chance_i(triggerAmount)) - return false; - triggered_spell_id = 64136; - target = this; - break; - } switch (dummySpell->Id) { - // Vampiric Embrace - case 15286: - { - if (!victim || !victim->IsAlive() || procSpell->SpellFamilyFlags[1] & 0x80000) - return false; - - // heal amount - int32 total = CalculatePct(int32(damage), triggerAmount); - int32 team = total / 5; - int32 self = total - team; - CastCustomSpell(this, 15290, &team, &self, NULL, true, castItem, triggeredByAura); - return true; // no hidden cooldown - } // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen) case 40438: { @@ -5910,29 +5588,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; break; } - // Improved Shadowform - case 47570: - case 47569: - { - if (!roll_chance_i(triggerAmount)) - return false; - - RemoveMovementImpairingAuras(); - break; - } - // Glyph of Dispel Magic - case 55677: - { - // Dispel Magic shares spellfamilyflag with abolish disease - if (procSpell->SpellIconID != 74) - return false; - if (!target || !target->IsFriendlyTo(this)) - return false; - - basepoints0 = int32(target->CountPctFromMaxHealth(triggerAmount)); - triggered_spell_id = 56131; - break; - } // Oracle Healing Bonus ("Garments of the Oracle" set) case 26169: { @@ -5979,25 +5634,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere { switch (dummySpell->Id) { - // Glyph of Innervate - case 54832: - { - if (procSpell->SpellIconID != 62) - return false; - - int32 mana_perc = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcValue(); - basepoints0 = int32(CalculatePct(GetCreatePowers(POWER_MANA), mana_perc) / 10); - triggered_spell_id = 54833; - target = this; - break; - } - // Glyph of Starfire - case 54845: - { - triggered_spell_id = 54846; - break; - } - // Glyph of Shred + // Glyph of Bloodletting case 54815: { if (!target) @@ -6006,15 +5643,14 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // try to find spell Rip on the target if (AuraEffect const* AurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, GetGUID())) { - // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip + // Rip's max duration, note: spells which modifies Rip's duration also counted uint32 CountMin = AurEff->GetBase()->GetMaxDuration(); // just Rip's max duration without other spells uint32 CountMax = AurEff->GetSpellInfo()->GetMaxDuration(); // add possible auras' and Glyph of Shred's max duration - CountMax += 3 * triggerAmount * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds - CountMax += HasAura(54818) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds + CountMax += 3 * triggerAmount * IN_MILLISECONDS; // Glyph of Bloodletting -> +6 seconds CountMax += HasAura(60141) ? 4 * IN_MILLISECONDS : 0; // Rip Duration/Lacerate Damage -> +4 seconds // if min < max -> that means caster didn't cast 3 shred yet @@ -6029,19 +5665,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // if not found Rip return false; } - // Glyph of Rake - case 54821: - { - if (procSpell->SpellVisual[0] == 750 && procSpell->Effects[1].ApplyAuraName == 3) - { - if (target && target->GetTypeId() == TYPEID_UNIT) - { - triggered_spell_id = 54820; - break; - } - } - return false; - } // Leader of the Pack case 24932: { @@ -6050,13 +5673,9 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); target = this; triggered_spell_id = 34299; - if (triggeredByAura->GetCasterGUID() != GetGUID()) - break; - int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2); - // Improved Leader of the Pack - // Check cooldown of heal spell cooldown - if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299)) - CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura); + // Regenerate 4% mana + int32 mana = CalculatePct(GetCreateMana(), triggerAmount); + CastCustomSpell(this, 68285, &mana, NULL, NULL, true, castItem, triggeredByAura); break; } // Healing Touch (Dreamwalker Raiment set) @@ -6068,15 +5687,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 28742; break; } - // Glyph of Rejuvenation - case 54754: - { - if (!victim || !victim->HealthBelowPct(uint32(triggerAmount))) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 54755; - break; - } // Healing Touch Refund (Idol of Longevity trinket) case 28847: { @@ -6124,13 +5734,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; break; } - // Maim Interrupt - case 44835: - { - // Deadly Interrupt Effect - triggered_spell_id = 32747; - break; - } // Item - Druid T10 Balance 4P Bonus case 70723: { @@ -6164,236 +5767,15 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return true; } } - // Eclipse - if (dummySpell->SpellIconID == 2856 && GetTypeId() == TYPEID_PLAYER) - { - if (!procSpell || effIndex != 0) - return false; - - bool isWrathSpell = (procSpell->SpellFamilyFlags[0] & 1); - - if (!roll_chance_f(dummySpell->ProcChance * (isWrathSpell ? 0.6f : 1.0f))) - return false; - - target = this; - if (target->HasAura(isWrathSpell ? 48517 : 48518)) - return false; - - triggered_spell_id = isWrathSpell ? 48518 : 48517; - break; - } - break; - } - case SPELLFAMILY_ROGUE: - { - switch (dummySpell->Id) - { - case 56800: // Glyph of Backstab - { - triggered_spell_id = 63975; - break; - } - case 32748: // Deadly Throw Interrupt - { - // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw - if (this == victim) - return false; - - triggered_spell_id = 32747; - break; - } - } - - switch (dummySpell->SpellIconID) - { - case 2116: // Quick Recovery - { - if (!procSpell) - return false; - - // energy cost save - basepoints0 = CalculatePct(int32(procSpell->ManaCost), triggerAmount); - if (basepoints0 <= 0) - return false; - - target = this; - triggered_spell_id = 31663; - break; - } - case 2909: // Cut to the Chase - { - // "refresh your Slice and Dice duration to its 5 combo point maximum" - // lookup Slice and Dice - if (AuraEffect const* aur = GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x40000, 0, 0)) - { - aur->GetBase()->SetDuration(aur->GetSpellInfo()->GetMaxDuration(), true); - return true; - } - return false; - } - case 2963: // Deadly Brew - { - triggered_spell_id = 3409; - break; - } - } - break; - } - case SPELLFAMILY_HUNTER: - { - switch (dummySpell->SpellIconID) - { - case 2236: // Thrill of the Hunt - { - if (!procSpell) - return false; - - Spell* spell = ToPlayer()->m_spellModTakingSpell; - - // Disable charge drop because of Lock and Load - ToPlayer()->SetSpellModTakingSpell(spell, false); - - // Explosive Shot - if (procSpell->SpellFamilyFlags[2] & 0x200) - { - if (!victim) - return false; - if (AuraEffect const* pEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x0, 0x80000000, 0x0, GetGUID())) - basepoints0 = pEff->GetSpellInfo()->CalcPowerCost(this, SpellSchoolMask(pEff->GetSpellInfo()->SchoolMask)) * 4/10/3; - } - else - basepoints0 = procSpell->CalcPowerCost(this, SpellSchoolMask(procSpell->SchoolMask)) * 4/10; - - ToPlayer()->SetSpellModTakingSpell(spell, true); - - if (basepoints0 <= 0) - return false; - - target = this; - triggered_spell_id = 34720; - break; - } - case 3406: // Hunting Party - { - triggered_spell_id = 57669; - target = this; - break; - } - case 3560: // Rapid Recuperation - { - // This effect only from Rapid Killing (mana regen) - if (!(procSpell->SpellFamilyFlags[1] & 0x01000000)) - return false; - - target = this; - - switch (dummySpell->Id) - { - case 53228: // Rank 1 - triggered_spell_id = 56654; - break; - case 53232: // Rank 2 - triggered_spell_id = 58882; - break; - } - break; - } - case 3579: // Lock and Load - { - // Proc only from periodic (from trap activation proc another aura of this spell) - if (!(procFlag & PROC_FLAG_DONE_PERIODIC) || !roll_chance_i(triggerAmount)) - return false; - triggered_spell_id = 56453; - target = this; - break; - } - } - - switch (dummySpell->Id) - { - case 57870: // Glyph of Mend Pet - { - victim->CastSpell(victim, 57894, true, NULL, NULL, GetGUID()); - return true; - } - } break; } case SPELLFAMILY_PALADIN: { - // Light's Beacon - Beacon of Light - if (dummySpell->Id == 53651) - { - if (!victim) - return false; - triggered_spell_id = 0; - Unit* beaconTarget = NULL; - if (GetTypeId() != TYPEID_PLAYER) - { - beaconTarget = triggeredByAura->GetBase()->GetCaster(); - if (!beaconTarget || beaconTarget == this || !(beaconTarget->GetAura(53563, victim->GetGUID()))) - return false; - basepoints0 = int32(damage); - triggered_spell_id = procSpell->IsRankOf(sSpellMgr->GetSpellInfo(635)) ? 53652 : 53654; - } - else - { // Check Party/Raid Group - if (Group* group = ToPlayer()->GetGroup()) - { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - if (Player* member = itr->GetSource()) - { - // check if it was heal by paladin which cast this beacon of light - if (member->GetAura(53563, victim->GetGUID())) - { - // do not proc when target of beacon of light is healed - if (member == this) - return false; - - beaconTarget = member; - basepoints0 = int32(damage); - triggered_spell_id = procSpell->IsRankOf(sSpellMgr->GetSpellInfo(635)) ? 53652 : 53654; - break; - } - } - } - } - } - - if (triggered_spell_id && beaconTarget) - { - victim->CastCustomSpell(beaconTarget, triggered_spell_id, &basepoints0, NULL, NULL, true); - return true; - } - - return false; - } // Judgements of the Wise if (dummySpell->SpellIconID == 3017) { target = this; triggered_spell_id = 31930; - // replenishment - CastSpell(this, 57669, true, castItem, triggeredByAura); - break; - } - // Righteous Vengeance - if (dummySpell->SpellIconID == 3025) - { - // 4 damage tick - basepoints0 = triggerAmount * damage / 400; - triggered_spell_id = 61840; - // Add remaining ticks to damage done - basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE); - break; - } - // Sheath of Light - if (dummySpell->SpellIconID == 3030) - { - // 4 healing tick - basepoints0 = triggerAmount * damage / 400; - triggered_spell_id = 54203; break; } switch (dummySpell->Id) @@ -6415,38 +5797,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; break; } - // Heart of the Crusader - case 20335: // rank 1 - triggered_spell_id = 21183; - break; - case 20336: // rank 2 - triggered_spell_id = 54498; - break; - case 20337: // rank 3 - triggered_spell_id = 54499; - break; - // Judgement of Light - case 20185: - { - if (!victim) - return false; - - // 2% of maximum health - basepoints0 = int32(victim->CountPctFromMaxHealth(2)); - victim->CastCustomSpell(victim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura); - return true; - } - // Judgement of Wisdom - case 20186: - { - if (victim && victim->IsAlive() && victim->getPowerType() == POWER_MANA) - { - // 2% of base mana - basepoints0 = int32(CalculatePct(victim->GetCreateMana(), 2)); - victim->CastCustomSpell(victim, 20268, &basepoints0, NULL, NULL, true, 0, triggeredByAura); - } - return true; - } // Holy Power (Redemption Armor set) case 28789: { @@ -6478,10 +5828,9 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } break; } - // Seal of Vengeance (damage calc on apply aura) case 31801: { - if (effIndex != 0) // effect 1, 2 used by seal unleashing code + if (effIndex != 0) // effect 2 used by seal unleashing code return false; // At melee attack or Hammer of the Righteous spell damage considered as melee attack @@ -6494,7 +5843,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 31803; - // On target with 5 stacks of Holy Vengeance direct damage is done + // On target with 5 stacks of Censure direct damage is done if (Aura* aur = victim->GetAura(triggered_spell_id, GetGUID())) { if (aur->GetStackAmount() == 5) @@ -6510,61 +5859,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return false; break; } - // Seal of Corruption - case 53736: - { - if (effIndex != 0) // effect 1, 2 used by seal unleashing code - return false; - - // At melee attack or Hammer of the Righteous spell damage considered as melee attack - bool stacker = !procSpell || procSpell->Id == 53595; - // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements - bool damager = procSpell && (procSpell->EquippedItemClass != -1 || (procSpell->SpellIconID == 243 && procSpell->SpellVisual[0] == 39)); - - if (!stacker && !damager) - return false; - - triggered_spell_id = 53742; - - // On target with 5 stacks of Blood Corruption direct damage is done - if (Aura* aur = victim->GetAura(triggered_spell_id, GetGUID())) - { - if (aur->GetStackAmount() == 5) - { - if (stacker) - aur->RefreshDuration(); - CastSpell(victim, 53739, true); - return true; - } - } - - if (!stacker) - return false; - break; - } - // Spiritual Attunement - case 31785: - case 33776: - { - // if healed by another unit (victim) - if (this == victim) - return false; - - // heal amount - basepoints0 = int32(CalculatePct(std::min(damage, GetMaxHealth() - GetHealth()), triggerAmount)); - target = this; - - if (basepoints0) - triggered_spell_id = 31786; - break; - } // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) case 40470: { if (!procSpell) return false; - float chance; + float chance; // Flash of light/Holy light if (procSpell->SpellFamilyFlags[0] & 0xC0000000) @@ -6586,13 +5887,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere break; } - // Glyph of Holy Light - case 54937: - { - triggered_spell_id = 54968; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - break; - } // Item - Paladin T8 Holy 2P Bonus case 64890: { @@ -6672,14 +5966,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere { switch (dummySpell->Id) { - // Tidal Force - case 55198: - { - // Remove aura stack from caster - RemoveAuraFromStack(55166); - // drop charges - return false; - } // Totemic Power (The Earthshatterer set) case 28823: { @@ -6752,26 +6038,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return false; // Now amount of extra power stored in 1 effect of Enchant spell - // Get it by item enchant id - uint32 spellId; - switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT))) - { - case 283: spellId = 8232; break; // 1 Rank - case 284: spellId = 8235; break; // 2 Rank - case 525: spellId = 10486; break; // 3 Rank - case 1669:spellId = 16362; break; // 4 Rank - case 2636:spellId = 25505; break; // 5 Rank - case 3785:spellId = 58801; break; // 6 Rank - case 3786:spellId = 58803; break; // 7 Rank - case 3787:spellId = 58804; break; // 8 Rank - default: - { - TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)", - castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)), dummySpell->Id); - return false; - } - } - + uint32 spellId = 8232; SpellInfo const* windfurySpellInfo = sSpellMgr->GetSpellInfo(spellId); if (!windfurySpellInfo) { @@ -6831,17 +6098,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; break; } - // Glyph of Healing Wave - case 55440: - { - // Not proc from self heals - if (this == victim) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - target = this; - triggered_spell_id = 55533; - break; - } // Spirit Hunt case 58877: { @@ -6914,23 +6170,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // if not found Flame Shock return false; } - case 63280: // Glyph of Totem of Wrath - { - if (procSpell->SpellIconID != 2019) - return false; - - if (Creature* totem = GetMap()->GetCreature(m_SummonSlot[1])) // Fire totem summon slot - { - if (SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(totem->m_spells[0])) - { - int32 bp0 = CalculatePct(totemSpell->Effects[EFFECT_0].CalcValue(), triggerAmount); - int32 bp1 = CalculatePct(totemSpell->Effects[EFFECT_1].CalcValue(), triggerAmount); - CastCustomSpell(this, 63283, &bp0, &bp1, NULL, true); - return true; - } - } - return false; - } break; } // Frozen Power @@ -6947,14 +6186,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 63685; break; } - // Ancestral Awakening - if (dummySpell->SpellIconID == 3065) - { - triggered_spell_id = 52759; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - target = this; - break; - } // Flametongue Weapon (Passive) if (dummySpell->SpellFamilyFlags[0] & 0x200000) { @@ -7002,109 +6233,19 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere CastCustomSpell(victim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); return true; } - // Improved Water Shield - if (dummySpell->SpellIconID == 2287) - { - // Default chance for Healing Wave and Riptide - float chance = (float)triggeredByAura->GetAmount(); - - if (procSpell->SpellFamilyFlags[0] & 0x80) - // Lesser Healing Wave - 0.6 of default - chance *= 0.6f; - else if (procSpell->SpellFamilyFlags[0] & 0x100) - // Chain heal - 0.3 of default - chance *= 0.3f; - - if (!roll_chance_f(chance)) - return false; - - // Water Shield - if (AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0, 0x00000020, 0)) - { - uint32 spell = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - CastSpell(this, spell, true, castItem, triggeredByAura); - return true; - } - return false; - } - // Lightning Overload - if (dummySpell->SpellIconID == 2018) // only this spell has SpellFamily Shaman SpellIconID == 2018 and dummy aura - { - if (!procSpell || GetTypeId() != TYPEID_PLAYER || !victim) - return false; - - // custom cooldown processing case - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(dummySpell->Id)) - return false; - - uint32 spellId = 0; - // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost - switch (procSpell->Id) - { - // Lightning Bolt - case 403: spellId = 45284; break; // Rank 1 - case 529: spellId = 45286; break; // Rank 2 - case 548: spellId = 45287; break; // Rank 3 - case 915: spellId = 45288; break; // Rank 4 - case 943: spellId = 45289; break; // Rank 5 - case 6041: spellId = 45290; break; // Rank 6 - case 10391: spellId = 45291; break; // Rank 7 - case 10392: spellId = 45292; break; // Rank 8 - case 15207: spellId = 45293; break; // Rank 9 - case 15208: spellId = 45294; break; // Rank 10 - case 25448: spellId = 45295; break; // Rank 11 - case 25449: spellId = 45296; break; // Rank 12 - case 49237: spellId = 49239; break; // Rank 13 - case 49238: spellId = 49240; break; // Rank 14 - // Chain Lightning - case 421: spellId = 45297; break; // Rank 1 - case 930: spellId = 45298; break; // Rank 2 - case 2860: spellId = 45299; break; // Rank 3 - case 10605: spellId = 45300; break; // Rank 4 - case 25439: spellId = 45301; break; // Rank 5 - case 25442: spellId = 45302; break; // Rank 6 - case 49270: spellId = 49268; break; // Rank 7 - case 49271: spellId = 49269; break; // Rank 8 - default: - TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id); - return false; - } - - // Chain Lightning - if (procSpell->SpellFamilyFlags[0] & 0x2) - { - // Chain lightning has [LightOverload_Proc_Chance] / [Max_Number_of_Targets] chance to proc of each individual target hit. - // A maxed LO would have a 33% / 3 = 11% chance to proc of each target. - // LO chance was already "accounted" at the proc chance roll, now need to divide the chance by [Max_Number_of_Targets] - float chance = 100.0f / procSpell->Effects[effIndex].ChainTarget; - if (!roll_chance_f(chance)) - return false; - - // Remove cooldown (Chain Lightning - has Category Recovery time) - ToPlayer()->RemoveSpellCooldown(spellId); - } - - CastSpell(victim, spellId, true, castItem, triggeredByAura); - - if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown); - - return true; - } // Static Shock if (dummySpell->SpellIconID == 3059) { // Lightning Shield - if (AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400, 0, 0)) + if (GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400, 0, 0)) { - uint32 spell = sSpellMgr->GetSpellWithRank(26364, aurEff->GetSpellInfo()->GetRank()); + uint32 spell = 26364; // custom cooldown processing case if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(spell)) ToPlayer()->RemoveSpellCooldown(spell); CastSpell(target, spell, true, castItem, triggeredByAura); - aurEff->GetBase()->DropCharge(); return true; } return false; @@ -7113,7 +6254,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } case SPELLFAMILY_DEATHKNIGHT: { - // Blood-Caked Strike - Blood-Caked Blade + // Blood-Caked Blade if (dummySpell->SpellIconID == 138) { if (!target || !target->IsAlive()) @@ -7122,22 +6263,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = dummySpell->Effects[effIndex].TriggerSpell; break; } - // Improved Blood Presence - if (dummySpell->SpellIconID == 2636) - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - break; - } - // Butchery - if (dummySpell->SpellIconID == 2664) - { - basepoints0 = triggerAmount; - triggered_spell_id = 50163; - target = this; - break; - } // Dancing Rune Weapon if (dummySpell->Id == 49028) { @@ -7163,13 +6288,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere else return false; } - // Mark of Blood - if (dummySpell->Id == 49005) - { - /// @todo need more info (cooldowns/PPM) - triggered_spell_id = 61607; - break; - } // Unholy Blight if (dummySpell->Id == 49194) { @@ -7188,21 +6306,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE); break; } - // Vendetta - if (dummySpell->SpellFamilyFlags[0] & 0x10000) - { - basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); - triggered_spell_id = 50181; - target = this; - break; - } - // Necrosis - if (dummySpell->SpellIconID == 2709) - { - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 51460; - break; - } // Threat of Thassarian if (dummySpell->SpellIconID == 2023) { @@ -7215,45 +6318,12 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere switch (procSpell->Id) { - // Obliterate - case 49020: triggered_spell_id = 66198; break; // Rank 1 - case 51423: triggered_spell_id = 66972; break; // Rank 2 - case 51424: triggered_spell_id = 66973; break; // Rank 3 - case 51425: triggered_spell_id = 66974; break; // Rank 4 - - // Frost Strike - case 49143: triggered_spell_id = 66196; break; // Rank 1 - case 51416: triggered_spell_id = 66958; break; // Rank 2 - case 51417: triggered_spell_id = 66959; break; // Rank 3 - case 51418: triggered_spell_id = 66960; break; // Rank 4 - case 51419: triggered_spell_id = 66961; break; // Rank 5 - case 55268: triggered_spell_id = 66962; break; // Rank 6 - - // Plague Strike - case 45462: triggered_spell_id = 66216; break; // Rank 1 - case 49917: triggered_spell_id = 66988; break; // Rank 2 - case 49918: triggered_spell_id = 66989; break; // Rank 3 - case 49919: triggered_spell_id = 66990; break; // Rank 4 - case 49920: triggered_spell_id = 66991; break; // Rank 5 - case 49921: triggered_spell_id = 66992; break; // Rank 6 - - // Death Strike - case 49998: triggered_spell_id = 66188; break; // Rank 1 - case 49999: triggered_spell_id = 66950; break; // Rank 2 - case 45463: triggered_spell_id = 66951; break; // Rank 3 - case 49923: triggered_spell_id = 66952; break; // Rank 4 - case 49924: triggered_spell_id = 66953; break; // Rank 5 - - // Rune Strike - case 56815: triggered_spell_id = 66217; break; // Rank 1 - - // Blood Strike - case 45902: triggered_spell_id = 66215; break; // Rank 1 - case 49926: triggered_spell_id = 66975; break; // Rank 2 - case 49927: triggered_spell_id = 66976; break; // Rank 3 - case 49928: triggered_spell_id = 66977; break; // Rank 4 - case 49929: triggered_spell_id = 66978; break; // Rank 5 - case 49930: triggered_spell_id = 66979; break; // Rank 6 + case 49020: triggered_spell_id = 66198; break; // Obliterate + case 49143: triggered_spell_id = 66196; break; // Frost Strike + case 45462: triggered_spell_id = 66216; break; // Plague Strike + case 49998: triggered_spell_id = 66188; break; // Death Strike + case 56815: triggered_spell_id = 66217; break; // Rune Strike + case 45902: triggered_spell_id = 66215; break; // Blood Strike default: return false; } @@ -7272,79 +6342,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; break; } - // Wandering Plague - if (dummySpell->SpellIconID == 1614) - { - if (!roll_chance_f(GetUnitCriticalChance(BASE_ATTACK, victim))) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 50526; - break; - } - // Sudden Doom - if (dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER) - { - SpellChainNode const* chain = NULL; - // get highest rank of the Death Coil spell - PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - // check if shown in spell book - if (!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED) - continue; - - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(itr->first); - if (!spellProto) - continue; - - if (spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT - && spellProto->SpellFamilyFlags[0] & 0x2000) - { - SpellChainNode const* newChain = sSpellMgr->GetSpellChainNode(itr->first); - - // No chain entry or entry lower than found entry - if (!chain || !newChain || (chain->rank < newChain->rank)) - { - triggered_spell_id = itr->first; - chain = newChain; - } - else - continue; - // Found spell is last in chain - do not need to look more - // Optimisation for most common case - if (chain && chain->last->Id == itr->first) - break; - } - } - } - break; - } - case SPELLFAMILY_POTION: - { - // alchemist's stone - if (dummySpell->Id == 17619) - { - if (procSpell->SpellFamilyName == SPELLFAMILY_POTION) - { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) - { - if (procSpell->Effects[i].Effect == SPELL_EFFECT_HEAL) - { - triggered_spell_id = 21399; - } - else if (procSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE) - { - triggered_spell_id = 21400; - } - else - continue; - - basepoints0 = int32(CalculateSpellDamage(this, procSpell, i) * 0.4f); - CastCustomSpell(this, triggered_spell_id, &basepoints0, NULL, NULL, true, NULL, triggeredByAura); - } - return true; - } - } break; } case SPELLFAMILY_PET: @@ -7407,9 +6404,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return true; } + /* + */ + + // Used in case when access to whole aura is needed // All procs should be handled like this... -bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 /*procFlag*/, uint32 procEx, uint32 cooldown, bool * handled) +bool Unit::HandleAuraProc(Unit* victim, uint32 /*damage*/, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown, bool * handled) { SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); @@ -7467,30 +6468,8 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp break; case SPELLFAMILY_PALADIN: { - // Infusion of Light - if (procSpell && dummySpell->SpellIconID == 3021) - { - // Flash of Light HoT on Flash of Light when Sacred Shield active - if (procSpell->SpellFamilyFlags[0] & 0x40000000 && procSpell->SpellIconID == 242) - { - *handled = true; - if (victim && victim->HasAura(53601)) - { - int32 bp0 = CalculatePct(int32(damage / 12), dummySpell->Effects[EFFECT_2].CalcValue()); - // Item - Paladin T9 Holy 4P Bonus - if (AuraEffect const* aurEff = GetAuraEffect(67191, 0)) - AddPct(bp0, aurEff->GetAmount()); - CastCustomSpell(victim, 66922, &bp0, NULL, NULL, true); - return true; - } - } - // but should not proc on non-critical Holy Shocks - else if ((procSpell->SpellFamilyFlags[0] & 0x200000 || procSpell->SpellFamilyFlags[1] & 0x10000) && !(procEx & PROC_EX_CRITICAL_HIT)) - *handled = true; - break; - } // Judgements of the Just - else if (dummySpell->SpellIconID == 3015) + if (dummySpell->SpellIconID == 3015) { *handled = true; CastSpell(victim, 68055, true); @@ -7521,24 +6500,8 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp } case SPELLFAMILY_MAGE: { - // Combustion switch (dummySpell->Id) { - case 11129: - { - *handled = true; - Unit* caster = triggeredByAura->GetCaster(); - if (!caster || !damage) - return false; - - // last charge and crit - if (triggeredByAura->GetCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT)) - return true; // charge counting (will removed) - - CastSpell(this, 28682, true); - - return (procEx & PROC_EX_CRITICAL_HIT) != 0; - } // Empowered Fire case 31656: case 31657: @@ -7629,13 +6592,6 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp } return true; } - // Hungering Cold aura drop - case 51209: - *handled = true; - // Drop only in not disease case - if (procSpell && procSpell->Dispel == DISPEL_DISEASE) - return false; - return true; } break; } @@ -7765,85 +6721,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg } } break; - case SPELLFAMILY_MAGE: - if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed - { - switch (auraSpellInfo->Id) - { - case 31641: // Rank 1 - case 31642: // Rank 2 - trigger_spell_id = 31643; - break; - default: - TC_LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell %u miss posibly Blazing Speed", auraSpellInfo->Id); - return false; - } - } - break; - case SPELLFAMILY_WARLOCK: - { - // Drain Soul - if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000) - { - // Improved Drain Soul - Unit::AuraEffectList const& mAddFlatModifier = GetAuraEffectsByType(SPELL_AURA_DUMMY); - for (Unit::AuraEffectList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i) - { - if ((*i)->GetMiscValue() == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellInfo()->SpellIconID == 113) - { - int32 value2 = CalculateSpellDamage(this, (*i)->GetSpellInfo(), 2); - basepoints0 = int32(CalculatePct(GetMaxPower(POWER_MANA), value2)); - // Drain Soul - CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - break; - } - } - // Not remove charge (aura removed on death in any cases) - // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura - return false; - } - // Nether Protection - else if (auraSpellInfo->SpellIconID == 1985) - { - if (!procSpell) - return false; - switch (GetFirstSchoolInMask(procSpell->GetSchoolMask())) - { - case SPELL_SCHOOL_NORMAL: - return false; // ignore - case SPELL_SCHOOL_HOLY: trigger_spell_id = 54370; break; - case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break; - case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break; - case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break; - case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break; - case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break; - default: - return false; - } - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Blessed Recovery - if (auraSpellInfo->SpellIconID == 1875) - { - switch (auraSpellInfo->Id) - { - case 27811: trigger_spell_id = 27813; break; - case 27815: trigger_spell_id = 27817; break; - case 27816: trigger_spell_id = 27818; break; - default: - TC_LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell %u not handled in BR", auraSpellInfo->Id); - return false; - } - basepoints0 = CalculatePct(int32(damage), triggerAmount) / 3; - target = this; - // Add remaining ticks to healing done - basepoints0 += GetRemainingPeriodicAmount(GetGUID(), trigger_spell_id, SPELL_AURA_PERIODIC_HEAL); - } - break; - } case SPELLFAMILY_DRUID: { switch (auraSpellInfo->Id) @@ -7855,8 +6732,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg { case FORM_NONE: trigger_spell_id = 37344; break; case FORM_CAT: trigger_spell_id = 37341; break; - case FORM_BEAR: - case FORM_DIREBEAR: trigger_spell_id = 37340; break; + case FORM_BEAR: trigger_spell_id = 37340; break; case FORM_TREE: trigger_spell_id = 37342; break; case FORM_MOONKIN: trigger_spell_id = 37343; break; default: @@ -7870,8 +6746,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg switch (GetShapeshiftForm()) { case FORM_CAT: trigger_spell_id = 67355; break; - case FORM_BEAR: - case FORM_DIREBEAR: trigger_spell_id = 67354; break; + case FORM_BEAR: trigger_spell_id = 67354; break; default: return false; } @@ -7980,124 +6855,14 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg break; } default: - // Illumination - if (auraSpellInfo->SpellIconID == 241) - { - if (!procSpell) - return false; - // procspell is triggered spell but we need mana cost of original cast spell - uint32 originalSpellId = procSpell->Id; - // Holy Shock heal - if (procSpell->SpellFamilyFlags[1] & 0x00010000) - { - switch (procSpell->Id) - { - case 25914: originalSpellId = 20473; break; - case 25913: originalSpellId = 20929; break; - case 25903: originalSpellId = 20930; break; - case 27175: originalSpellId = 27174; break; - case 33074: originalSpellId = 33072; break; - case 48820: originalSpellId = 48824; break; - case 48821: originalSpellId = 48825; break; - default: - TC_LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell %u not handled in HShock", procSpell->Id); - return false; - } - } - SpellInfo const* originalSpell = sSpellMgr->GetSpellInfo(originalSpellId); - if (!originalSpell) - { - TC_LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu", originalSpellId); - return false; - } - // percent stored in effect 1 (class scripts) base points - int32 cost = int32(originalSpell->ManaCost + CalculatePct(GetCreateMana(), originalSpell->ManaCostPercentage)); - basepoints0 = CalculatePct(cost, auraSpellInfo->Effects[1].CalcValue()); - trigger_spell_id = 20272; - target = this; - } break; } break; } - case SPELLFAMILY_SHAMAN: - { - switch (auraSpellInfo->Id) - { - case 30881: // Nature's Guardian Rank 1 - case 30883: // Nature's Guardian Rank 2 - case 30884: // Nature's Guardian Rank 3 - case 30885: // Nature's Guardian Rank 4 - case 30886: // Nature's Guardian Rank 5 - { - if (HealthBelowPct(30)) - { - basepoints0 = int32(auraSpellInfo->Effects[EFFECT_0].CalcValue() * GetMaxHealth() / 100.0f); - target = this; - trigger_spell_id = 31616; - /// @todo Threat part - } - else - return false; - break; - } - default: - { - // Lightning Shield (overwrite non existing triggered spell call in spell.dbc - if (auraSpellInfo->SpellFamilyFlags[0] & 0x400) - { - trigger_spell_id = sSpellMgr->GetSpellWithRank(26364, auraSpellInfo->GetRank()); - } - // Nature's Guardian - else if (auraSpellInfo->SpellIconID == 2013) - { - // Check health condition - should drop to less 30% (damage deal after this!) - if (!HealthBelowPctDamaged(30, damage)) - return false; - - if (victim && victim->IsAlive()) - victim->getThreatManager().modifyThreatPercent(this, -10); - - basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); - trigger_spell_id = 31616; - target = this; - } - } - } - break; - } case SPELLFAMILY_DEATHKNIGHT: { - // Acclimation - if (auraSpellInfo->SpellIconID == 1930) - { - if (!procSpell) - return false; - switch (GetFirstSchoolInMask(procSpell->GetSchoolMask())) - { - case SPELL_SCHOOL_NORMAL: - return false; // ignore - case SPELL_SCHOOL_HOLY: trigger_spell_id = 50490; break; - case SPELL_SCHOOL_FIRE: trigger_spell_id = 50362; break; - case SPELL_SCHOOL_NATURE: trigger_spell_id = 50488; break; - case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break; - case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; break; - case SPELL_SCHOOL_ARCANE: trigger_spell_id = 50486; break; - default: - return false; - } - } - // Blood Presence (Improved) - else if (auraSpellInfo->Id == 63611) - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - trigger_spell_id = 50475; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - } // Item - Death Knight T10 Melee 4P Bonus - else if (auraSpellInfo->Id == 70656) + if (auraSpellInfo->Id == 70656) { if (GetTypeId() != TYPEID_PLAYER || getClass() != CLASS_DEATH_KNIGHT) return false; @@ -8181,7 +6946,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg // Deflection case 52420: { - if (!HealthBelowPct(35)) + if (!HealthBelowPctDamaged(35, damage)) return false; break; } @@ -8194,16 +6959,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg return false; break; } - // Deadly Swiftness (Rank 1) - case 31255: - { - // whenever you deal damage to a target who is below 20% health. - if (!victim || !victim->IsAlive() || victim->HealthAbovePct(20)) - return false; - - target = this; - trigger_spell_id = 22588; - } // Greater Heal Refund (Avatar Raiment set) case 37594: { @@ -8226,36 +6981,17 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg return false; break; } - // Rapid Recuperation - case 53228: - case 53232: - { - // This effect only from Rapid Fire (ability cast) - if (!(procSpell->SpellFamilyFlags[0] & 0x20)) - return false; - break; - } // Decimation case 63156: case 63158: - // Can proc only if target has hp below 35% - if (!victim || !victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, procSpell, this)) + // Can proc only if target has hp below 25% + if (!victim || !victim->HealthBelowPct(auraSpellInfo->Effects[EFFECT_1].CalcValue())) return false; break; // Deathbringer Saurfang - Blood Beast's Blood Link case 72176: basepoints0 = 3; break; - case 15337: // Improved Spirit Tap (Rank 1) - case 15338: // Improved Spirit Tap (Rank 2) - { - if (procSpell->SpellFamilyFlags[0] & 0x800000) - if ((procSpell->Id != 58381) || !roll_chance_i(50)) - return false; - - target = victim; - break; - } // Professor Putricide - Ooze Spell Tank Protection case 71770: if (victim) @@ -8276,52 +7012,11 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg break; } - // Blade Barrier - if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 85 && procSpell) - { - Player* player = ToPlayer(); - if (!player || player->getClass() != CLASS_DEATH_KNIGHT) - return false; - - if (!player->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD)) - return false; - } - - // Rime - else if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 56) - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - // Howling Blast - ToPlayer()->RemoveSpellCategoryCooldown(1248, true); - } - // Custom basepoints/target for exist spell // dummy basepoints or other customs switch (trigger_spell_id) { // Auras which should proc on area aura source (caster in this case): - // Turn the Tables - case 52914: - case 52915: - case 52910: - // Honor Among Thieves - case 52916: - { - target = triggeredByAura->GetBase()->GetCaster(); - if (!target) - return false; - - if (cooldown && target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->HasSpellCooldown(trigger_spell_id)) - return false; - - target->CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura); - - if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown); - return true; - } // Cast positive spell on enemy target case 7099: // Curse of Mending case 39703: // Curse of Mending @@ -8331,14 +7026,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg target = victim; break; } - // Combo points add triggers (need add combopoint only for main target, and after possible combopoints reset) - case 15250: // Rogue Setup - { - // applied only for main target - if (!victim || (GetTypeId() == TYPEID_PLAYER && victim != ToPlayer()->GetSelectedUnit())) - return false; - break; // continue normal case - } // Finish movies that add combo case 14189: // Seal Fate (Netherblade set) case 14157: // Ruthlessness @@ -8355,12 +7042,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg CastSpell(this, 70721, true); break; } - // Shamanistic Rage triggered spell - case 30824: - { - basepoints0 = int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), triggerAmount)); - break; - } // Enlightenment (trigger only from mana cost spells) case 35095: { @@ -8368,22 +7049,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg return false; break; } - // Demonic Pact - case 48090: - { - // Get talent aura from owner - if (IsPet()) - if (Unit* owner = GetOwner()) - { - if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3220, 0)) - { - basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonusDone(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f); /// @todo Is it right? - CastCustomSpell(this, trigger_spell_id, &basepoints0, &basepoints0, NULL, true, castItem, triggeredByAura); - return true; - } - } - break; - } case 46916: // Slam! (Bloodsurge proc) case 52437: // Sudden Death { @@ -8398,14 +7063,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg } break; } - // Sword and Board - case 50227: - { - // Remove cooldown on Shield Slam - if (GetTypeId() == TYPEID_PLAYER) - ToPlayer()->RemoveSpellCategoryCooldown(1209, true); - break; - } // Maelstrom Weapon case 53817: { @@ -8422,35 +7079,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg CastSpell(this, 70831, true, castItem, triggeredByAura); break; } - // Astral Shift - case 52179: - { - if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim) - return false; - - // Need stun, fear or silence mechanic - if (!(procSpell->GetAllEffectsMechanicMask() & ((1<<MECHANIC_SILENCE)|(1<<MECHANIC_STUN)|(1<<MECHANIC_FEAR)))) - return false; - break; - } - // Burning Determination - case 54748: - { - if (!procSpell) - return false; - // Need Interrupt or Silenced mechanic - if (!(procSpell->GetAllEffectsMechanicMask() & ((1<<MECHANIC_INTERRUPT)|(1<<MECHANIC_SILENCE)))) - return false; - break; - } - // Lock and Load - case 56453: - { - // Proc only from Frost/Freezing trap activation or from Freezing Arrow (the periodic dmg proc handled elsewhere) - if (!(procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION) || !procSpell || !(procSpell->SchoolMask & SPELL_SCHOOL_MASK_FROST) || !roll_chance_i(triggerAmount)) - return false; - break; - } // Glyph of Death's Embrace case 58679: { @@ -8459,14 +7087,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg return false; break; } - // Glyph of Death Grip - case 58628: - { - // remove cooldown of Death Grip - if (GetTypeId() == TYPEID_PLAYER) - ToPlayer()->RemoveSpellCooldown(49576, true); - return true; - } // Savage Defense case 62606: { @@ -8513,7 +7133,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg return true; } -bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown) +bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 cooldown) { int32 scriptId = triggeredByAura->GetMiscValue(); @@ -8527,27 +7147,6 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, Au switch (scriptId) { - case 836: // Improved Blizzard (Rank 1) - { - if (!procSpell || procSpell->SpellVisual[0] != 9487) - return false; - triggered_spell_id = 12484; - break; - } - case 988: // Improved Blizzard (Rank 2) - { - if (!procSpell || procSpell->SpellVisual[0] != 9487) - return false; - triggered_spell_id = 12485; - break; - } - case 989: // Improved Blizzard (Rank 3) - { - if (!procSpell || procSpell->SpellVisual[0] != 9487) - return false; - triggered_spell_id = 12486; - break; - } case 4533: // Dreamwalker Raiment 2 pieces bonus { // Chance 50% @@ -8567,26 +7166,6 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, Au case 4537: // Dreamwalker Raiment 6 pieces bonus triggered_spell_id = 28750; // Blessing of the Claw break; - case 5497: // Improved Mana Gems - triggered_spell_id = 37445; // Mana Surge - break; - case 7010: // Revitalize - can proc on full hp target - case 7011: - case 7012: - { - if (!roll_chance_i(triggeredByAura->GetAmount())) - return false; - switch (victim->getPowerType()) - { - case POWER_MANA: triggered_spell_id = 48542; break; - case POWER_RAGE: triggered_spell_id = 48541; break; - case POWER_ENERGY: triggered_spell_id = 48540; break; - case POWER_RUNIC_POWER: triggered_spell_id = 48543; break; - default: - break; - } - break; - } default: break; } @@ -8658,10 +7237,6 @@ void Unit::setPowerType(Powers new_powertype) case POWER_ENERGY: SetMaxPower(POWER_ENERGY, uint32(std::ceil(GetCreatePowers(POWER_ENERGY) * powerMultiplier))); break; - case POWER_HAPPINESS: - SetMaxPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier))); - SetPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier))); - break; } } @@ -9149,7 +7724,7 @@ bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit co { AuraEffectList const& stateAuras = Caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); for (AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j) - if ((*j)->IsAffectedOnSpell(spellProto)) + if ((*j)->IsAffectingSpell(spellProto)) return true; } // Check per caster aura state @@ -9183,7 +7758,7 @@ void Unit::SetOwnerGUID(uint64 owner) SetFieldNotifyFlag(UF_FLAG_OWNER); - UpdateData udata; + UpdateData udata(GetMapId()); WorldPacket packet; BuildValuesUpdateBlockForPlayer(&udata, player); udata.BuildPacket(&packet); @@ -9228,7 +7803,7 @@ Player* Unit::GetAffectingPlayer() const return NULL; } -Minion *Unit::GetFirstMinion() const +Minion* Unit::GetFirstMinion() const { if (uint64 pet_guid = GetMinionGUID()) { @@ -9494,10 +8069,7 @@ void Unit::SetCharm(Unit* charm, bool apply) _isWalkingBeforeCharm = charm->IsWalking(); if (_isWalkingBeforeCharm) - { charm->SetWalk(false); - charm->SendMovementFlagUpdate(); - } m_Controlled.insert(charm); } @@ -9532,10 +8104,7 @@ void Unit::SetCharm(Unit* charm, bool apply) } if (charm->IsWalking() != _isWalkingBeforeCharm) - { charm->SetWalk(_isWalkingBeforeCharm); - charm->SendMovementFlagUpdate(true); // send packet to self, to update movement state on player. - } if (charm->GetTypeId() == TYPEID_PLAYER || !charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_MINION) @@ -9574,7 +8143,7 @@ int32 Unit::DealHeal(Unit* victim, uint32 addhealth) // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria) if (gain) - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, victim); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, 0, victim); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth); } @@ -9850,7 +8419,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { - if (!(*i)->IsAffectedOnSpell(spellProto)) + if (!(*i)->IsAffectingSpell(spellProto)) continue; switch ((*i)->GetMiscValue()) @@ -10009,26 +8578,40 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage if (victim->HasAuraState(AuraStateType((*i)->GetMiscValue()))) AddPct(DoneTotalMod, (*i)->GetAmount()); + // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus + AddPct(DoneTotalMod, GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC, spellProto->Mechanic)); + // done scripted mod (take it from owner) Unit const* owner = GetOwner() ? GetOwner() : this; AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { - if (!(*i)->IsAffectedOnSpell(spellProto)) + if (!(*i)->IsAffectingSpell(spellProto)) continue; switch ((*i)->GetMiscValue()) { case 4920: // Molten Fury case 4919: - case 6917: // Death's Embrace - case 6926: - case 6928: { if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) AddPct(DoneTotalMod, (*i)->GetAmount()); break; } + case 6917: // Death's Embrace damage effect + case 6926: + case 6928: + { + // Health at 25% or less (25% stored at effect 2 of the spell) + if (victim->HealthBelowPct(CalculateSpellDamage(this, (*i)->GetSpellInfo(), EFFECT_2))) + AddPct(DoneTotalMod, (*i)->GetAmount()); + } + case 6916: // Death's Embrace heal effect + case 6925: + case 6927: + if (HealthBelowPct(CalculateSpellDamage(this, (*i)->GetSpellInfo(), EFFECT_2))) + AddPct(DoneTotalMod, (*i)->GetAmount()); + break; // Soul Siphon case 4992: case 4993: @@ -10056,77 +8639,12 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage AddPct(DoneTotalMod, modPercent); break; } - case 6916: // Death's Embrace - case 6925: - case 6927: - if (HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, spellProto, this)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - break; case 5481: // Starfire Bonus { if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x200002, 0, 0)) AddPct(DoneTotalMod, (*i)->GetAmount()); break; } - // Tundra Stalker - // Merciless Combat - case 7277: - { - // Merciless Combat - if ((*i)->GetSpellInfo()->SpellIconID == 2656) - { - if (!victim->HealthAbovePct(35)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - } - // Tundra Stalker - else - { - // Frost Fever (target debuff) - if (victim->HasAura(55095)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - break; - } - break; - } - // Rage of Rivendare - case 7293: - { - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0x02000000, 0)) - AddPct(DoneTotalMod, (*i)->GetSpellInfo()->GetRank() * 2.0f); - break; - } - // Twisted Faith - case 7377: - { - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID())) - AddPct(DoneTotalMod, (*i)->GetAmount()); - break; - } - // Marked for Death - case 7598: - case 7599: - case 7600: - case 7601: - case 7602: - { - if (victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - break; - } - // Dirty Deeds - case 6427: - case 6428: - case 6579: - case 6580: - { - if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) - { - // effect 0 has expected value but in negative state - int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount(); - AddPct(DoneTotalMod, bonus); - } - break; - } } } @@ -10136,89 +8654,35 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage case SPELLFAMILY_MAGE: // Ice Lance if (spellProto->SpellIconID == 186) - { if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) - { - // Glyph of Ice Lance - if (owner->HasAura(56377) && victim->getLevel() > owner->getLevel()) - DoneTotalMod *= 4.0f; - else - DoneTotalMod *= 3.0f; - } - } + DoneTotalMod *= 2.0f; // Torment the weak - if (spellProto->SpellFamilyFlags[0] & 0x20600021 || spellProto->SpellFamilyFlags[1] & 0x9000) + if (spellProto->GetSchoolMask() & SPELL_SCHOOL_MASK_ARCANE) + { if (victim->HasAuraWithMechanic((1<<MECHANIC_SNARE)|(1<<MECHANIC_SLOW_ATTACK))) { AuraEffectList const& mDumyAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY); for (AuraEffectList::const_iterator i = mDumyAuras.begin(); i != mDumyAuras.end(); ++i) - if ((*i)->GetSpellInfo()->SpellIconID == 3263) + { + if ((*i)->GetSpellInfo()->SpellIconID == 2215) { AddPct(DoneTotalMod, (*i)->GetAmount()); break; } + } } + } break; case SPELLFAMILY_PRIEST: - // Mind Flay - if (spellProto->SpellFamilyFlags[0] & 0x800000) - { - // Glyph of Shadow Word: Pain - if (AuraEffect* aurEff = GetAuraEffect(55687, 0)) - // Increase Mind Flay damage if Shadow Word: Pain present on target - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID())) - AddPct(DoneTotalMod, aurEff->GetAmount()); - - // Twisted Faith - Mind Flay part - if (AuraEffect* aurEff = GetAuraEffect(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, SPELLFAMILY_PRIEST, 2848, 1)) - // Increase Mind Flay damage if Shadow Word: Pain present on target - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID())) - AddPct(DoneTotalMod, aurEff->GetAmount()); - } // Smite - else if (spellProto->SpellFamilyFlags[0] & 0x80) + if (spellProto->SpellFamilyFlags[0] & 0x80) { // Glyph of Smite if (AuraEffect* aurEff = GetAuraEffect(55692, 0)) if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, GetGUID())) AddPct(DoneTotalMod, aurEff->GetAmount()); } - // Shadow Word: Death - else if (spellProto->SpellFamilyFlags[1] & 0x2) - { - // Glyph of Shadow Word: Death - if (AuraEffect* aurEff = GetAuraEffect(55682, 1)) - if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) - AddPct(DoneTotalMod, aurEff->GetAmount()); - } - break; - case SPELLFAMILY_PALADIN: - // Judgement of Vengeance/Judgement of Corruption - if ((spellProto->SpellFamilyFlags[1] & 0x400000) && spellProto->SpellIconID == 2292) - { - // Get stack of Holy Vengeance/Blood Corruption on the target added by caster - uint32 stacks = 0; - Unit::AuraEffectList const& auras = victim->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE); - for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - if (((*itr)->GetId() == 31803 || (*itr)->GetId() == 53742) && (*itr)->GetCasterGUID() == GetGUID()) - { - stacks = (*itr)->GetBase()->GetStackAmount(); - break; - } - // + 10% for each application of Holy Vengeance/Blood Corruption on the target - if (stacks) - AddPct(DoneTotalMod, 10 * stacks); - } - break; - case SPELLFAMILY_DRUID: - // Thorns - if (spellProto->SpellFamilyFlags[0] & 0x100) - { - // Brambles - if (AuraEffect* aurEff = GetAuraEffectOfRankedSpell(16836, 0)) - AddPct(DoneTotalMod, aurEff->GetAmount()); - } break; case SPELLFAMILY_WARLOCK: // Fire and Brimstone @@ -10233,33 +8697,22 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage break; } } - // Shadow Bite (15% increase from each dot) + + // Shadow Bite (30% increase from each dot) if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet()) if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID())) - AddPct(DoneTotalMod, 15 * count); + AddPct(DoneTotalMod, 30 * count); - // Drain Soul - If the target is at or below 25% health, Drain Soul causes four times the normal damage - if (spellProto->SpellFamilyFlags[0] & 0x00004000 && !victim->HealthAbovePct(25)) - DoneTotalMod *= 4; - break; - case SPELLFAMILY_HUNTER: - // Steady Shot - if (spellProto->SpellFamilyFlags[1] & 0x1) - if (AuraEffect* aurEff = GetAuraEffect(56826, 0)) // Glyph of Steady Shot - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_HUNTER, 0x00004000, 0, 0, GetGUID())) - AddPct(DoneTotalMod, aurEff->GetAmount()); + // Drain Soul - increased damage for targets under 25 % HP + if (spellProto->SpellFamilyFlags[0] & 0x00004000) + if (HasAura(100001)) + DoneTotalMod *= 2; break; case SPELLFAMILY_DEATHKNIGHT: - // Improved Icy Touch - if (spellProto->SpellFamilyFlags[0] & 0x2) - if (AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2721, 0)) - AddPct(DoneTotalMod, aurEff->GetAmount()); - - // Glacier Rot - if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6) - if (AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 196, 0)) - if (victim->GetDiseasesByCaster(owner->GetGUID()) > 0) - AddPct(DoneTotalMod, aurEff->GetAmount()); + // Sigil of the Vengeful Heart + if (spellProto->SpellFamilyFlags[0] & 0x2000) + if (AuraEffect* aurEff = GetAuraEffect(64962, EFFECT_1)) + DoneTotalMod += aurEff->GetAmount(); break; } @@ -10293,13 +8746,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui // Cheat Death case 2109: if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - { - // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap - // is 22.5% critical strike damage reduction, or 444 resilience. - // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%) - float mod = -1.0f * GetMeleeCritDamageReduction(400); - AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount()))); - } + AddPct(TakenTotalMod, (*i)->GetAmount()); break; } } @@ -10314,14 +8761,10 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui TakenTotalCasterMod += (float((*i)->GetAmount())); } - // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN - // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085) - TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, spellProto->GetSchoolMask()); - // From caster spells AuraEffectList const& mOwnerTaken = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER); for (AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i) - if ((*i)->GetCasterGUID() == caster->GetGUID() && (*i)->IsAffectedOnSpell(spellProto)) + if ((*i)->GetCasterGUID() == caster->GetGUID() && (*i)->IsAffectingSpell(spellProto)) AddPct(TakenTotalMod, (*i)->GetAmount()); int32 TakenAdvertisedBenefit = SpellBaseDamageBonusTaken(spellProto->GetSchoolMask()); @@ -10388,6 +8831,10 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const // Base value DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus(); + // Check if we are ever using mana - PaperDollFrame.lua + if (GetPowerIndex(POWER_MANA) != MAX_POWERS) + DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect + // Damage bonus from stats AuraEffectList const& mDamageDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT); for (AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i) @@ -10475,29 +8922,21 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto crit_chance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask); // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE crit_chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE); - ApplyResilience(victim, &crit_chance, NULL, false, CR_CRIT_TAKEN_SPELL); } // scripted (increase crit chance ... against ... target by x% AuraEffectList const& mOverrideClassScript = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { - if (!((*i)->IsAffectedOnSpell(spellProto))) + if (!((*i)->IsAffectingSpell(spellProto))) continue; switch ((*i)->GetMiscValue()) { - case 911: // Shatter (Rank 1) + // Shatter + case 911: if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) - crit_chance += 17; + AddPct(crit_chance, (*i)->GetAmount()*20); break; - case 910: // Shatter (Rank 2) - if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) - crit_chance += 34; - break; - case 849: // Shatter (Rank 3) - if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) - crit_chance += 50; - break; case 7917: // Glyph of Shadowburn if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) crit_chance+=(*i)->GetAmount(); @@ -10592,16 +9031,6 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto break; } break; - case SPELLFAMILY_WARRIOR: - // Victory Rush - if (spellProto->SpellFamilyFlags[1] & 0x100) - { - // Glyph of Victory Rush - if (AuraEffect const* aurEff = GetAuraEffect(58382, 0)) - crit_chance += aurEff->GetAmount(); - break; - } - break; } } /// Intentional fallback. Calculate critical strike chance for both Ranged and Melee spells @@ -10622,10 +9051,15 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); + AuraEffectList const& critAuras = victim->GetAuraEffectsByType(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER); + for (AuraEffectList::const_iterator i = critAuras.begin(); i != critAuras.end(); ++i) + if ((*i)->GetCasterGUID() == GetGUID() && (*i)->IsAffectingSpell(spellProto)) + crit_chance += (*i)->GetAmount(); + return crit_chance > 0.0f ? crit_chance : 0.0f; } -uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim) +uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* /*victim*/) { // Calculate critical bonus int32 crit_bonus = damage; @@ -10645,9 +9079,6 @@ uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage crit_mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100; - if (victim) - crit_mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, victim->GetCreatureTypeMask()); - if (crit_bonus != 0) AddPct(crit_bonus, crit_mod); @@ -10665,30 +9096,12 @@ uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage return crit_bonus; } -uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim) +uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* /*spellProto*/, uint32 damage, Unit* /*victim*/) { // Calculate critical bonus - int32 crit_bonus; - switch (spellProto->DmgClass) - { - case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% - case SPELL_DAMAGE_CLASS_RANGED: - /// @todo write here full calculation for melee/ranged spells - crit_bonus = damage; - break; - default: - crit_bonus = damage / 2; // for spells is 50% - break; - } - - if (victim) - { - uint32 creatureTypeMask = victim->GetCreatureTypeMask(); - crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask)); - } + int32 crit_bonus = damage; - if (crit_bonus > 0) - damage += crit_bonus; + damage += crit_bonus; damage = int32(float(damage) * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT)); @@ -10713,7 +9126,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { - if (!(*i)->IsAffectedOnSpell(spellProto)) + if (!(*i)->IsAffectingSpell(spellProto)) continue; switch ((*i)->GetMiscValue()) { @@ -10722,6 +9135,31 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind DoneTotal += (*i)->GetAmount(); break; + case 21: // Test of Faith + case 6935: + case 6918: + if (victim->HealthBelowPct(50)) + AddPct(DoneTotal, (*i)->GetAmount()); + break; + case 8477: // Nourish Heal Boost + { + int32 stepPercent = (*i)->GetAmount(); + int32 modPercent = 0; + AuraApplicationMap const& victimAuras = victim->GetAppliedAuras(); + for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr) + { + Aura const* aura = itr->second->GetBase(); + if (aura->GetCasterGUID() != GetGUID()) + continue; + SpellInfo const* m_spell = aura->GetSpellInfo(); + if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID || + !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50)) + continue; + modPercent += stepPercent * aura->GetStackAmount(); + } + AddPct(DoneTotal, modPercent); + break; + } default: break; } @@ -10773,10 +9211,6 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui coeff /= 100.0f; } - // Earthliving - 0.45% of normal hot coeff - if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags[1] & 0x80000) - factorMod *= 0.45f; - DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); } @@ -10825,8 +9259,9 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { - if (!(*i)->IsAffectedOnSpell(spellProto)) + if (!(*i)->IsAffectingSpell(spellProto)) continue; + switch ((*i)->GetMiscValue()) { case 21: // Test of Faith @@ -10906,18 +9341,6 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u TakenTotalMod *= 1.2f; } - if (damagetype == DOT) - { - // Healing over time taken percent - float minval_hot = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT)); - if (minval_hot) - AddPct(TakenTotalMod, minval_hot); - - float maxval_hot = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT)); - if (maxval_hot) - AddPct(TakenTotalMod, maxval_hot); - } - // Check for table values SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); float coeff = 0; @@ -10948,16 +9371,12 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u coeff /= 100.0f; } - // Earthliving - 0.45% of normal hot coeff - if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags[1] & 0x80000) - factorMod *= 0.45f; - TakenTotal += int32(TakenAdvertisedBenefit * coeff * factorMod); } AuraEffectList const& mHealingGet= GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_RECEIVED); for (AuraEffectList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i) - if (caster->GetGUID() == (*i)->GetCasterGUID() && (*i)->IsAffectedOnSpell(spellProto)) + if (caster->GetGUID() == (*i)->GetCasterGUID() && (*i)->IsAffectingSpell(spellProto)) AddPct(TakenTotalMod, (*i)->GetAmount()); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -10994,6 +9413,10 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const // Base value advertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus(); + // Check if we are ever using mana - PaperDollFrame.lua + if (GetPowerIndex(POWER_MANA) != MAX_POWERS) + advertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT)) - 10); // spellpower from intellect + // Healing bonus from stats AuraEffectList const& mHealingDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT); for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i) @@ -11260,80 +9683,13 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType if (victim->HasAuraState(AuraStateType((*i)->GetMiscValue()))) AddPct(DoneTotalMod, (*i)->GetAmount()); - // done scripted mod (take it from owner) - Unit* owner = GetOwner() ? GetOwner() : this; - AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) - { - if (!(*i)->IsAffectedOnSpell(spellProto)) - continue; - - switch ((*i)->GetMiscValue()) - { - // Tundra Stalker - // Merciless Combat - case 7277: - { - // Merciless Combat - if ((*i)->GetSpellInfo()->SpellIconID == 2656) - { - if (!victim->HealthAbovePct(35)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - } - // Tundra Stalker - else - { - // Frost Fever (target debuff) - if (victim->HasAura(55095)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - } - break; - } - // Rage of Rivendare - case 7293: - { - if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0x02000000, 0)) - AddPct(DoneTotalMod, (*i)->GetSpellInfo()->GetRank() * 2.0f); - break; - } - // Marked for Death - case 7598: - case 7599: - case 7600: - case 7601: - case 7602: - { - if (victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - break; - } - // Dirty Deeds - case 6427: - case 6428: - { - if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) - { - // effect 0 has expected value but in negative state - int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount(); - AddPct(DoneTotalMod, bonus); - } - break; - } - } - } - - // Custom scripted damage + // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus if (spellProto) - switch (spellProto->SpellFamilyName) - { - case SPELLFAMILY_DEATHKNIGHT: - // Glacier Rot - if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6) - if (AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 196, 0)) - if (victim->GetDiseasesByCaster(owner->GetGUID()) > 0) - AddPct(DoneTotalMod, aurEff->GetAmount()); - break; - } + AddPct(DoneTotalMod, GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC, spellProto->Mechanic)); + + // done scripted mod (take it from owner) + // Unit* owner = GetOwner() ? GetOwner() : this; + // AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); float tmpDamage = float(int32(pdamage) + DoneFlatBenefit) * DoneTotalMod; @@ -11386,7 +9742,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT // From caster spells AuraEffectList const& mOwnerTaken = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER); for (AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i) - if ((*i)->GetCasterGUID() == attacker->GetGUID() && (*i)->IsAffectedOnSpell(spellProto)) + if ((*i)->GetCasterGUID() == attacker->GetGUID() && (*i)->IsAffectingSpell(spellProto)) AddPct(TakenTotalMod, (*i)->GetAmount()); // Mod damage from spell mechanic @@ -11415,11 +9771,11 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT case 2109: if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) { - // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap - // is 22.5% critical strike damage reduction, or 444 resilience. - // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%) - float mod = -1.0f * GetMeleeCritDamageReduction(400); - AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount()))); + if (Player* player = ToPlayer()) + { + float mod = player->GetRatingBonusValue(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN) * (-8.0f); + AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount()))); + } } break; } @@ -11568,8 +9924,7 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry) data << uint32(VehicleId); SendMessageToSet(&data, true); - data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); - player->GetSession()->SendPacket(&data); + player->SendOnCancelExpectedVehicleRideAura(); // mounts can also have accessories GetVehicleKit()->InstallAllAccessories(false); @@ -11588,11 +9943,7 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry) player->UnsummonPetTemporaryIfAny(); } - WorldPacket data(SMSG_MOVE_SET_COLLISION_HGT, GetPackGUID().size() + 4 + 4); - data.append(GetPackGUID()); - data << uint32(sWorld->GetGameTime()); // Packet counter - data << player->GetCollisionHeight(true); - player->GetSession()->SendPacket(&data); + player->SendMovementSetCollisionHeight(player->GetCollisionHeight(true)); } RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNT); @@ -11607,13 +9958,7 @@ void Unit::Dismount() RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT); if (Player* thisPlayer = ToPlayer()) - { - WorldPacket data(SMSG_MOVE_SET_COLLISION_HGT, GetPackGUID().size() + 4 + 4); - data.append(GetPackGUID()); - data << uint32(sWorld->GetGameTime()); // Packet counter - data << thisPlayer->GetCollisionHeight(false); - thisPlayer->GetSession()->SendPacket(&data); - } + thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight(false)); WorldPacket data(SMSG_DISMOUNT, 8); data.appendPackGUID(GetGUID()); @@ -11648,6 +9993,64 @@ void Unit::Dismount() } } +MountCapabilityEntry const* Unit::GetMountCapability(uint32 mountType) const +{ + if (!mountType) + return NULL; + + MountTypeEntry const* mountTypeEntry = sMountTypeStore.LookupEntry(mountType); + if (!mountTypeEntry) + return NULL; + + uint32 zoneId, areaId; + GetZoneAndAreaId(zoneId, areaId); + uint32 ridingSkill = 5000; + if (GetTypeId() == TYPEID_PLAYER) + ridingSkill = ToPlayer()->GetSkillValue(SKILL_RIDING); + + for (uint32 i = MAX_MOUNT_CAPABILITIES; i > 0; --i) + { + MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(mountTypeEntry->MountCapability[i - 1]); + if (!mountCapability) + continue; + + if (ridingSkill < mountCapability->RequiredRidingSkill) + continue; + + if (HasExtraUnitMovementFlag(MOVEMENTFLAG2_FULL_SPEED_PITCHING)) + { + if (!(mountCapability->Flags & MOUNT_FLAG_CAN_PITCH)) + continue; + } + else if (HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING)) + { + if (!(mountCapability->Flags & MOUNT_FLAG_CAN_SWIM)) + continue; + } + else if (!(mountCapability->Flags & 0x1)) // unknown flags, checked in 4.2.2 14545 client + { + if (!(mountCapability->Flags & 0x2)) + continue; + } + + if (mountCapability->RequiredMap != -1 && int32(GetMapId()) != mountCapability->RequiredMap) + continue; + + if (mountCapability->RequiredArea && (mountCapability->RequiredArea != zoneId && mountCapability->RequiredArea != areaId)) + continue; + + if (mountCapability->RequiredAura && !HasAura(mountCapability->RequiredAura)) + continue; + + if (mountCapability->RequiredSpell && (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->HasSpell(mountCapability->RequiredSpell))) + continue; + + return mountCapability; + } + + return NULL; +} + bool Unit::IsServiceProvider() const { return HasFlag(UNIT_NPC_FLAGS, @@ -11851,13 +10254,17 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo if (playerAttacker->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_UBER)) return false; } + // check flags if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_TAXI_FLIGHT | UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_UNK_16) || (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC)) - || (!target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC)) - || (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC)) + || (!target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC))) + return false; + + if ((!bySpell || !(bySpell->AttributesEx8 & SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG)) + && (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC)) // check if this is a world trigger cast - GOs are using world triggers to cast their spells, so we need to ignore their immunity flag here, this is a temp workaround, needs removal when go cast is implemented properly - || (GetEntry() != WORLD_TRIGGER && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC))) + && GetEntry() != WORLD_TRIGGER) return false; // CvC case - can attack each other only when one of them is hostile @@ -12084,16 +10491,16 @@ int32 Unit::ModifyPower(Powers power, int32 dVal) if (dVal == 0) return 0; - int32 curPower = (int32)GetPower(power); + int32 curPower = GetPower(power); int32 val = dVal + curPower; - if (val <= 0) + if (val <= GetMinPower(power)) { - SetPower(power, 0); + SetPower(power, GetMinPower(power)); return -curPower; } - int32 maxPower = (int32)GetMaxPower(power); + int32 maxPower = GetMaxPower(power); if (val < maxPower) { @@ -12115,7 +10522,7 @@ int32 Unit::ModifyPowerPct(Powers power, float pct, bool apply) float amount = (float)GetMaxPower(power); ApplyPercentModFloatVar(amount, pct, apply); - return ModifyPower(power, (int32)amount - (int32)GetMaxPower(power)); + return ModifyPower(power, (int32)amount - GetMaxPower(power)); } uint32 Unit::GetAttackTime(WeaponAttackType att) const @@ -12328,100 +10735,35 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) propagateSpeedChange(); - WorldPacket data; - if (!forced) + static Opcodes const moveTypeToOpcode[MAX_MOVE_TYPE][3] = + { + {SMSG_SPLINE_MOVE_SET_WALK_SPEED, SMSG_MOVE_SET_WALK_SPEED, SMSG_MOVE_UPDATE_WALK_SPEED }, + {SMSG_SPLINE_MOVE_SET_RUN_SPEED, SMSG_MOVE_SET_RUN_SPEED, SMSG_MOVE_UPDATE_RUN_SPEED }, + {SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED, SMSG_MOVE_SET_RUN_BACK_SPEED, SMSG_MOVE_UPDATE_RUN_BACK_SPEED }, + {SMSG_SPLINE_MOVE_SET_SWIM_SPEED, SMSG_MOVE_SET_SWIM_SPEED, SMSG_MOVE_UPDATE_SWIM_SPEED }, + {SMSG_SPLINE_MOVE_SET_SWIM_BACK_SPEED, SMSG_MOVE_SET_SWIM_BACK_SPEED, SMSG_MOVE_UPDATE_SWIM_BACK_SPEED }, + {SMSG_SPLINE_MOVE_SET_TURN_RATE, SMSG_MOVE_SET_TURN_RATE, SMSG_MOVE_UPDATE_TURN_RATE }, + {SMSG_SPLINE_MOVE_SET_FLIGHT_SPEED, SMSG_MOVE_SET_FLIGHT_SPEED, SMSG_MOVE_UPDATE_FLIGHT_SPEED }, + {SMSG_SPLINE_MOVE_SET_FLIGHT_BACK_SPEED, SMSG_MOVE_SET_FLIGHT_BACK_SPEED, SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED}, + {SMSG_SPLINE_MOVE_SET_PITCH_RATE, SMSG_MOVE_SET_PITCH_RATE, SMSG_MOVE_UPDATE_PITCH_RATE }, + }; + + if (GetTypeId() == TYPEID_PLAYER) { - switch (mtype) - { - case MOVE_WALK: - data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_RUN: - data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_RUN_BACK: - data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_SWIM: - data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_SWIM_BACK: - data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_TURN_RATE: - data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_FLIGHT: - data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_FLIGHT_BACK: - data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); - break; - case MOVE_PITCH_RATE: - data.Initialize(MSG_MOVE_SET_PITCH_RATE, 8+4+2+4+4+4+4+4+4+4); - break; - default: - TC_LOG_ERROR("entities.unit", "Unit::SetSpeed: Unsupported move type (%d), data not sent to client.", mtype); - return; - } + // register forced speed changes for WorldSession::HandleForceSpeedChangeAck + // and do it only for real sent packets and use run for run/mounted as client expected + ++ToPlayer()->m_forced_speed_changes[mtype]; - BuildMovementPacket(&data); - data << float(GetSpeed(mtype)); - SendMessageToSet(&data, true); + if (!IsInCombat()) + if (Pet* pet = ToPlayer()->GetPet()) + pet->SetSpeed(mtype, m_speed_rate[mtype], forced); } - else - { - if (GetTypeId() == TYPEID_PLAYER) - { - // register forced speed changes for WorldSession::HandleForceSpeedChangeAck - // and do it only for real sent packets and use run for run/mounted as client expected - ++ToPlayer()->m_forced_speed_changes[mtype]; - if (!IsInCombat()) - if (Pet* pet = ToPlayer()->GetPet()) - pet->SetSpeed(mtype, m_speed_rate[mtype], forced); - } + static MovementStatusElements const speedVal = MSEExtraFloat; + Movement::ExtraMovementStatusElement extra(&speedVal); + extra.Data.floatData = GetSpeed(mtype); - switch (mtype) - { - case MOVE_WALK: - data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16); - break; - case MOVE_RUN: - data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 17); - break; - case MOVE_RUN_BACK: - data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16); - break; - case MOVE_SWIM: - data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16); - break; - case MOVE_SWIM_BACK: - data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16); - break; - case MOVE_TURN_RATE: - data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16); - break; - case MOVE_FLIGHT: - data.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE, 16); - break; - case MOVE_FLIGHT_BACK: - data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16); - break; - case MOVE_PITCH_RATE: - data.Initialize(SMSG_FORCE_PITCH_RATE_CHANGE, 16); - break; - default: - TC_LOG_ERROR("entities.unit", "Unit::SetSpeed: Unsupported move type (%d), data not sent to client.", mtype); - return; - } - data.append(GetPackGUID()); - data << (uint32)0; // moveEvent, NUM_PMOVE_EVTS = 0x39 - if (mtype == MOVE_RUN) - data << uint8(0); // new 2.1.0 - data << float(GetSpeed(mtype)); - SendMessageToSet(&data, true); - } + Movement::PacketSender(this, moveTypeToOpcode[mtype][0], moveTypeToOpcode[mtype][1], moveTypeToOpcode[mtype][2], &extra).Send(); } void Unit::setDeathState(DeathState s) @@ -12868,20 +11210,6 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in duration += aurEff->GetAmount() * MINUTE * IN_MILLISECONDS; } break; - case SPELLFAMILY_PALADIN: - if ((spellProto->SpellFamilyFlags[0] & 0x00000002) && spellProto->SpellIconID == 298) - { - // Glyph of Blessing of Might - if (AuraEffect* aurEff = GetAuraEffect(57958, 0)) - duration += aurEff->GetAmount() * MINUTE * IN_MILLISECONDS; - } - else if ((spellProto->SpellFamilyFlags[0] & 0x00010000) && spellProto->SpellIconID == 306) - { - // Glyph of Blessing of Wisdom - if (AuraEffect* aurEff = GetAuraEffect(57979, 0)) - duration += aurEff->GetAmount() * MINUTE * IN_MILLISECONDS; - } - break; } } return std::max(duration, 0); @@ -13054,7 +11382,7 @@ uint32 Unit::GetCreatureType() const if (GetTypeId() == TYPEID_PLAYER) { ShapeshiftForm form = GetShapeshiftForm(); - SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(form); + SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form); if (ssEntry && ssEntry->creatureType > 0) return ssEntry->creatureType; else @@ -13078,14 +11406,14 @@ void Unit::SetShapeshiftForm(ShapeshiftForm form) bool Unit::IsInFeralForm() const { ShapeshiftForm form = GetShapeshiftForm(); - return form == FORM_CAT || form == FORM_BEAR || form == FORM_DIREBEAR; + return form == FORM_CAT || form == FORM_BEAR; } bool Unit::IsInDisallowedMountForm() const { if (ShapeshiftForm form = GetShapeshiftForm()) { - SpellShapeshiftEntry const* shapeshift = sSpellShapeshiftStore.LookupEntry(form); + SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(form); if (!shapeshift) return true; @@ -13160,7 +11488,6 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f case UNIT_MOD_RAGE: case UNIT_MOD_FOCUS: case UNIT_MOD_ENERGY: - case UNIT_MOD_HAPPINESS: case UNIT_MOD_RUNE: case UNIT_MOD_RUNIC_POWER: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break; @@ -13280,8 +11607,7 @@ Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const case UNIT_MOD_RAGE: return POWER_RAGE; case UNIT_MOD_FOCUS: return POWER_FOCUS; case UNIT_MOD_ENERGY: return POWER_ENERGY; - case UNIT_MOD_HAPPINESS: return POWER_HAPPINESS; - case UNIT_MOD_RUNE: return POWER_RUNE; + case UNIT_MOD_RUNE: return POWER_RUNES; case UNIT_MOD_RUNIC_POWER: return POWER_RUNIC_POWER; default: case UNIT_MOD_MANA: return POWER_MANA; @@ -13292,14 +11618,14 @@ float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const { if (attType == RANGED_ATTACK) { - int32 ap = GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS); + int32 ap = GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER); if (ap < 0) return 0.0f; return ap * (1.0f + GetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER)); } else { - int32 ap = GetInt32Value(UNIT_FIELD_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS); + int32 ap = GetInt32Value(UNIT_FIELD_ATTACK_POWER); if (ap < 0) return 0.0f; return ap * (1.0f + GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER)); @@ -13394,22 +11720,45 @@ void Unit::SetMaxHealth(uint32 val) SetHealth(val); } -void Unit::SetPower(Powers power, uint32 val) +int32 Unit::GetPower(Powers power) const { - if (GetPower(power) == val) + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == MAX_POWERS) + return 0; + + return GetUInt32Value(UNIT_FIELD_POWER1 + powerIndex); +} + +int32 Unit::GetMaxPower(Powers power) const +{ + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == MAX_POWERS) + return 0; + + return GetInt32Value(UNIT_FIELD_MAXPOWER1 + powerIndex); +} + +void Unit::SetPower(Powers power, int32 val) +{ + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == MAX_POWERS) return; - uint32 maxPower = GetMaxPower(power); + int32 maxPower = int32(GetMaxPower(power)); if (maxPower < val) val = maxPower; - SetStatInt32Value(UNIT_FIELD_POWER1 + power, val); + SetInt32Value(UNIT_FIELD_POWER1 + powerIndex, val); - WorldPacket data(SMSG_POWER_UPDATE); - data.append(GetPackGUID()); - data << uint8(power); - data << uint32(val); - SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER); + if (IsInWorld()) + { + WorldPacket data(SMSG_POWER_UPDATE, 8 + 4 + 1 + 4); + data.append(GetPackGUID()); + data << uint32(1); //power count + data << uint8(powerIndex); + data << int32(val); + SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER); + } // group update if (Player* player = ToPlayer()) @@ -13425,17 +11774,17 @@ void Unit::SetPower(Powers power, uint32 val) if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); } - - // Update the pet's character sheet with happiness damage bonus - if (pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS) - pet->UpdateDamagePhysical(BASE_ATTACK); } } -void Unit::SetMaxPower(Powers power, uint32 val) +void Unit::SetMaxPower(Powers power, int32 val) { - uint32 cur_power = GetPower(power); - SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + power, val); + uint32 powerIndex = GetPowerIndex(power); + if (powerIndex == MAX_POWERS) + return; + + int32 cur_power = GetPower(power); + SetInt32Value(UNIT_FIELD_MAXPOWER1 + powerIndex, val); // group update if (GetTypeId() == TYPEID_PLAYER) @@ -13457,19 +11806,45 @@ void Unit::SetMaxPower(Powers power, uint32 val) SetPower(power, val); } -uint32 Unit::GetCreatePowers(Powers power) const +uint32 Unit::GetPowerIndex(uint32 powerType) const +{ + /// This is here because hunter pets are of the warrior class. + /// With the current implementation, the core only gives them + /// POWER_RAGE, so we enforce the class to hunter so that they + /// effectively get focus power. + uint32 classId = getClass(); + if (ToPet() && ToPet()->getPetType() == HUNTER_PET) + classId = CLASS_HUNTER; + + return GetPowerIndexByClass(powerType, classId); +} + +int32 Unit::GetCreatePowers(Powers power) const { - // Only hunter pets have POWER_FOCUS and POWER_HAPPINESS switch (power) { - case POWER_MANA: return GetCreateMana(); - case POWER_RAGE: return 1000; - case POWER_FOCUS: return (GetTypeId() == TYPEID_PLAYER || !((Creature const*)this)->IsPet() || ((Pet const*)this)->getPetType() != HUNTER_PET ? 0 : 100); - case POWER_ENERGY: return 100; - case POWER_HAPPINESS: return (GetTypeId() == TYPEID_PLAYER || !((Creature const*)this)->IsPet() || ((Pet const*)this)->getPetType() != HUNTER_PET ? 0 : 1050000); - case POWER_RUNIC_POWER: return 1000; - case POWER_RUNE: return 0; - case POWER_HEALTH: return 0; + case POWER_MANA: + return GetCreateMana(); + case POWER_RAGE: + return 1000; + case POWER_FOCUS: + if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_HUNTER) + return 100; + return (GetTypeId() == TYPEID_PLAYER || !((Creature const*)this)->IsPet() || ((Pet const*)this)->getPetType() != HUNTER_PET ? 0 : 100); + case POWER_ENERGY: + return 100; + case POWER_RUNIC_POWER: + return 1000; + case POWER_RUNES: + return 0; + case POWER_SOUL_SHARDS: + return 3; + case POWER_ECLIPSE: + return 100; + case POWER_HOLY_POWER: + return 3; + case POWER_HEALTH: + return 0; default: break; } @@ -13890,6 +12265,7 @@ bool InitTriggerAuraData() isNonTriggerAura[i] = false; isAlwaysTriggeredAura[i] = false; } + isTriggerAura[SPELL_AURA_PROC_ON_POWER_AMOUNT] = true; isTriggerAura[SPELL_AURA_DUMMY] = true; isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; isTriggerAura[SPELL_AURA_MOD_THREAT] = true; @@ -13914,11 +12290,13 @@ bool InitTriggerAuraData() isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true; isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true; isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true; + isTriggerAura[SPELL_AURA_MOD_POWER_REGEN_PERCENT] = true; isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true; isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true; isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true; isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true; + isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE_3] = true; isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true; isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true; isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true; @@ -13988,19 +12366,6 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u // For melee/ranged based attack need update skills and set some Aura states if victim present if (procFlag & MELEE_BASED_TRIGGER_MASK && target) { - // Update skills here for players - if (GetTypeId() == TYPEID_PLAYER) - { - // On melee based hit/miss/resist need update skill (for victim and attacker) - if (procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_MISS|PROC_EX_RESIST)) - { - if (target->GetTypeId() != TYPEID_PLAYER && target->GetCreatureType() != CREATURE_TYPE_CRITTER) - ToPlayer()->UpdateCombatSkills(target, attType, isVictim); - } - // Update defence if player is victim and parry/dodge/block - else if (isVictim && procExtra & (PROC_EX_DODGE|PROC_EX_PARRY|PROC_EX_BLOCK)) - ToPlayer()->UpdateCombatSkills(target, attType, true); - } // If exist crit/parry/dodge/block need update aura state (for victim and attacker) if (procExtra & (PROC_EX_CRITICAL_HIT|PROC_EX_PARRY|PROC_EX_DODGE|PROC_EX_BLOCK)) { @@ -14181,6 +12546,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u switch (triggeredByAura->GetAuraType()) { case SPELL_AURA_PROC_TRIGGER_SPELL: + case SPELL_AURA_PROC_TRIGGER_SPELL_2: { TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); // Don`t drop charge or add cooldown for not started trigger @@ -14206,10 +12572,19 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u takeCharges = true; break; } + case SPELL_AURA_PROC_ON_POWER_AMOUNT: + { + TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + if (HandleAuraProcOnPowerAmount(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges = true; + break; + } case SPELL_AURA_OBS_MOD_POWER: case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: + case SPELL_AURA_MOD_POWER_REGEN_PERCENT: case SPELL_AURA_MOD_MELEE_HASTE: + case SPELL_AURA_MOD_MELEE_HASTE_3: TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, isVictim ? "a victim's" : "an attacker's", triggeredByAura->GetId()); takeCharges = true; break; @@ -14248,7 +12623,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u } case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: // Skip melee hits or instant cast spells - if (procSpell && procSpell->CalcCastTime() != 0) + if (procSpell && procSpell->CalcCastTime(getLevel()) > 0) takeCharges = true; break; case SPELL_AURA_REFLECT_SPELLS_SCHOOL: @@ -14489,13 +12864,6 @@ void Unit::StopMoving() init.Stop(); } -void Unit::SendMovementFlagUpdate(bool self /* = false */) -{ - WorldPacket data; - BuildHeartBeatMsg(&data); - SendMessageToSet(&data, self); -} - bool Unit::IsSitState() const { uint8 s = getStandState(); @@ -14679,11 +13047,27 @@ void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply { ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply); ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att, val, !apply); + + if (GetTypeId() == TYPEID_PLAYER) + { + if (att == BASE_ATTACK) + ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE, val, !apply); + else if (att == RANGED_ATTACK) + ApplyPercentModFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE, val, !apply); + } } else { ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply); ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att, -val, apply); + + if (GetTypeId() == TYPEID_PLAYER) + { + if (att == BASE_ATTACK) + ApplyPercentModFloatValue(PLAYER_FIELD_MOD_HASTE, -val, apply); + else if (att == RANGED_ATTACK) + ApplyPercentModFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE, -val, apply); + } } m_attackTimer[att] = uint32(GetAttackTime(att) * m_modAttackSpeedPct[att] * remainingTimePct); } @@ -14691,9 +13075,15 @@ void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply void Unit::ApplyCastTimePercentMod(float val, bool apply) { if (val > 0) + { ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, val, !apply); + ApplyPercentModFloatValue(UNIT_MOD_CAST_HASTE, val, !apply); + } else + { ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED, -val, apply); + ApplyPercentModFloatValue(UNIT_MOD_CAST_HASTE, -val, apply); + } } uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectType damagetype, uint32 CastingTime) const @@ -14751,7 +13141,7 @@ uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectTyp if (overTime > 0 && CastingTime > 0 && DirectDamage) { // mainly for DoTs which are 3500 here otherwise - uint32 OriginalCastTime = spellProto->CalcCastTime(); + uint32 OriginalCastTime = spellProto->CalcCastTime(getLevel()); if (OriginalCastTime > 7000) OriginalCastTime = 7000; if (OriginalCastTime < 1500) OriginalCastTime = 1500; // Portion to Over Time @@ -14840,7 +13230,7 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect DotFactor /= DotTicks; } - int32 CastingTime = spellInfo->IsChanneled() ? spellInfo->GetDuration() : spellInfo->CalcCastTime(); + int32 CastingTime = spellInfo->IsChanneled() ? spellInfo->GetDuration() : spellInfo->CalcCastTime(getLevel()); // Distribute Damage over multiple effects, reduce by AoE CastingTime = GetCastingTimeForBonus(spellInfo, damagetype, CastingTime); @@ -14873,11 +13263,6 @@ float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) } } -bool Unit::IsUnderLastManaUseEffect() const -{ - return getMSTimeDiff(m_lastManaUse, getMSTime()) < 5000; -} - void Unit::SetContestedPvP(Player* attackedPlayer) { Player* player = GetCharmerOrOwnerPlayerOrPlayerItself(); @@ -15182,6 +13567,21 @@ bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura) return true; } +void Unit::SendDurabilityLoss(Player* receiver, uint32 percent) +{ + WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 4); + data << uint32(percent); + receiver->GetSession()->SendPacket(&data); +} + +void Unit::PlayOneShotAnimKit(uint32 id) +{ + WorldPacket data(SMSG_PLAY_ONE_SHOT_ANIM_KIT, 7+2); + data.appendPackGUID(GetGUID()); + data << uint16(id); + SendMessageToSet(&data, true); +} + void Unit::Kill(Unit* victim, bool durabilityLoss) { // Prevent killing unit twice (and giving reward from kill twice) @@ -15290,7 +13690,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) // update get killing blow achievements, must be done before setDeathState to be able to require auras on target // and before Spirit of Redemption as it also removes auras if (Player* killerPlayer = GetCharmerOrOwnerPlayerOrPlayerItself()) - killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, victim); + killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, 0, victim); // if talent known but not triggered (check priest class for speedup check) bool spiritOfRedemption = false; @@ -15346,11 +13746,13 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) // only if not player and not controlled by player pet. And not at BG if ((durabilityLoss && !player && !victim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP))) { - TC_LOG_DEBUG("entities.unit", "We are dead, losing %f percent durability", sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH)); - plrVictim->DurabilityLossAll(sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH), false); + double baseLoss = sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH); + uint32 loss = uint32(baseLoss - (baseLoss * plrVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_DURABILITY_LOSS))); + TC_LOG_DEBUG("entities.unit", "We are dead, losing %u percent durability", loss); + // Durability loss is calculated more accurately again for each item in Player::DurabilityLoss + plrVictim->DurabilityLossAll(baseLoss, false); // durability lost message - WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); - plrVictim->GetSession()->SendPacket(&data); + SendDurabilityLoss(plrVictim, loss); } // Call KilledUnit for creatures if (GetTypeId() == TYPEID_UNIT && IsAIEnabled) @@ -15534,7 +13936,8 @@ void Unit::SetControlled(bool apply, UnitState state) if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle()) return; - SetRooted(false); + if (!HasUnitState(UNIT_STATE_STUNNED)) + SetRooted(false); break; case UNIT_STATE_CONFUSED: if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) @@ -15576,22 +13979,13 @@ void Unit::SetStunned(bool apply) SetTarget(0); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a) - // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before - // setting MOVEMENTFLAG_ROOT - RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING); - AddUnitMovementFlag(MOVEMENTFLAG_ROOT); - // Creature specific if (GetTypeId() != TYPEID_PLAYER) StopMoving(); else SetStandState(UNIT_STAND_STATE_STAND); - WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8); - data.append(GetPackGUID()); - data << uint32(0); - SendMessageToSet(&data, true); + SetRooted(true); CastStop(); } @@ -15606,66 +14000,30 @@ void Unit::SetStunned(bool apply) RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); if (!HasUnitState(UNIT_STATE_ROOT)) // prevent moving if it also has root effect - { - WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 8+4); - data.append(GetPackGUID()); - data << uint32(0); - SendMessageToSet(&data, true); - - RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT); - } + SetRooted(false); } } -void Unit::SetRooted(bool apply) +void Unit::SetRooted(bool apply, bool packetOnly /*= false*/) { - if (apply) + if (!packetOnly) { - if (m_rootTimes > 0) // blizzard internal check? - m_rootTimes++; - - // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a) - // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before - // setting MOVEMENTFLAG_ROOT - RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING); - AddUnitMovementFlag(MOVEMENTFLAG_ROOT); - - if (GetTypeId() == TYPEID_PLAYER) + if (apply) { - WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10); - data.append(GetPackGUID()); - data << m_rootTimes; - SendMessageToSet(&data, true); + // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a) + // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before + // setting MOVEMENTFLAG_ROOT + RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING); + AddUnitMovementFlag(MOVEMENTFLAG_ROOT); } else - { - WorldPacket data(SMSG_SPLINE_MOVE_ROOT, 8); - data.append(GetPackGUID()); - SendMessageToSet(&data, true); - StopMoving(); - } - } - else - { - if (!HasUnitState(UNIT_STATE_STUNNED)) // prevent moving if it also has stun effect - { - if (GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10); - data.append(GetPackGUID()); - data << ++m_rootTimes; - SendMessageToSet(&data, true); - } - else - { - WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, 8); - data.append(GetPackGUID()); - SendMessageToSet(&data, true); - } - RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT); - } } + + if (apply) + Movement::PacketSender(this, SMSG_SPLINE_MOVE_ROOT, SMSG_MOVE_ROOT, SMSG_MOVE_ROOT).Send(); + else + Movement::PacketSender(this, SMSG_SPLINE_MOVE_UNROOT, SMSG_MOVE_UNROOT, SMSG_MOVE_UNROOT).Send(); } void Unit::SetFeared(bool apply) @@ -16199,33 +14557,43 @@ void Unit::SetAuraStack(uint32 spellId, Unit* target, uint32 stack) aura->SetStackAmount(stack); } -void Unit::SendPlaySpellVisual(uint32 id) -{ - WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 8 + 4); - data << uint64(GetGUID()); - data << uint32(id); // SpellVisualKit.dbc index - SendMessageToSet(&data, false); -} - -void Unit::SendPlaySpellImpact(uint64 guid, uint32 id) -{ - WorldPacket data(SMSG_PLAY_SPELL_IMPACT, 8 + 4); - data << uint64(guid); // target - data << uint32(id); // SpellVisualKit.dbc index - SendMessageToSet(&data, false); +void Unit::SendPlaySpellVisualKit(uint32 id, uint32 unkParam) +{ + ObjectGuid guid = GetGUID(); + + WorldPacket data(SMSG_PLAY_SPELL_VISUAL_KIT, 4 + 4+ 4 + 8); + data << uint32(0); + data << uint32(id); // SpellVisualKit.dbc index + data << uint32(unkParam); + data.WriteBit(guid[4]); + data.WriteBit(guid[7]); + data.WriteBit(guid[5]); + data.WriteBit(guid[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[2]); + data.WriteBit(guid[0]); + data.WriteBit(guid[6]); + data.FlushBits(); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[5]); + SendMessageToSet(&data, true); } -void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type) const +void Unit::ApplyResilience(Unit const* victim, int32* damage) const { // player mounted on multi-passenger mount is also classified as vehicle if (IsVehicle() || (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)) return; - Unit const* source = NULL; - if (GetTypeId() == TYPEID_PLAYER) - source = this; - else if (GetTypeId() == TYPEID_UNIT && GetOwner() && GetOwner()->GetTypeId() == TYPEID_PLAYER) - source = GetOwner(); + // Don't consider resilience if not in PvP - player or pet + if (!GetCharmerOrOwnerPlayerOrPlayerItself()) + return; Unit const* target = NULL; if (victim->GetTypeId() == TYPEID_PLAYER) @@ -16236,49 +14604,12 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool if (!target) return; - switch (type) - { - case CR_CRIT_TAKEN_MELEE: - // Crit chance reduction works against nonpets - if (crit) - *crit -= target->GetMeleeCritChanceReduction(); - if (source && damage) - { - if (isCrit) - *damage -= target->GetMeleeCritDamageReduction(*damage); - *damage -= target->GetMeleeDamageReduction(*damage); - } - break; - case CR_CRIT_TAKEN_RANGED: - // Crit chance reduction works against nonpets - if (crit) - *crit -= target->GetRangedCritChanceReduction(); - if (source && damage) - { - if (isCrit) - *damage -= target->GetRangedCritDamageReduction(*damage); - *damage -= target->GetRangedDamageReduction(*damage); - } - break; - case CR_CRIT_TAKEN_SPELL: - // Crit chance reduction works against nonpets - if (crit) - *crit -= target->GetSpellCritChanceReduction(); - if (source && damage) - { - if (isCrit) - *damage -= target->GetSpellCritDamageReduction(*damage); - *damage -= target->GetSpellDamageReduction(*damage); - } - break; - default: - break; - } + *damage -= target->GetDamageReduction(*damage); } // Melee based spells can be miss, parry or dodge on this step // Crit or block - determined on damage calculation phase! (and can be both in some time) -float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const +float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, uint32 spellId) const { //calculate miss chance float missChance = victim->GetUnitMissChance(attType); @@ -16286,14 +14617,6 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, i if (!spellId && haveOffhandWeapon()) missChance += 19; - // bonus from skills is 0.04% - //miss_chance -= skillDiff * 0.04f; - int32 diff = -skillDiff; - if (victim->GetTypeId() == TYPEID_PLAYER) - missChance += diff > 0 ? diff * 0.04f : diff * 0.02f; - else - missChance += diff > 10 ? 1 + (diff - 10) * 0.4f : diff * 0.1f; - // Calculate hit chance float hitChance = 100.0f; @@ -16319,67 +14642,54 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, i return missChance; } -void Unit::SetPhaseMask(uint32 newPhaseMask, bool update) +void Unit::SetInPhase(uint32 id, bool update, bool apply) { - if (newPhaseMask == GetPhaseMask()) + WorldObject::SetInPhase(id, update, apply); + + if (!IsInWorld()) return; - if (IsInWorld()) + RemoveNotOwnSingleTargetAuras(0, true); + + if (GetTypeId() == TYPEID_UNIT || (!ToPlayer()->IsGameMaster() && !ToPlayer()->GetSession()->PlayerLogout())) { - RemoveNotOwnSingleTargetAuras(newPhaseMask); // we can lost access to caster or target + HostileRefManager& refManager = getHostileRefManager(); + HostileReference* ref = refManager.getFirst(); - // modify hostile references for new phasemask, some special cases deal with hostile references themselves - if (GetTypeId() == TYPEID_UNIT || (!ToPlayer()->IsGameMaster() && !ToPlayer()->GetSession()->PlayerLogout())) + while (ref) { - HostileRefManager& refManager = getHostileRefManager(); - HostileReference* ref = refManager.getFirst(); + if (Unit* unit = ref->GetSource()->GetOwner()) + if (Creature* creature = unit->ToCreature()) + refManager.setOnlineOfflineState(creature, creature->IsInPhase(this)); - while (ref) - { - if (Unit* unit = ref->GetSource()->GetOwner()) - if (Creature* creature = unit->ToCreature()) - refManager.setOnlineOfflineState(creature, creature->InSamePhase(newPhaseMask)); - - ref = ref->next(); - } + ref = ref->next(); + } - // modify threat lists for new phasemask - if (GetTypeId() != TYPEID_PLAYER) - { - std::list<HostileReference*> threatList = getThreatManager().getThreatList(); - std::list<HostileReference*> offlineThreatList = getThreatManager().getOfflineThreatList(); + // modify threat lists for new phasemask + if (GetTypeId() != TYPEID_PLAYER) + { + std::list<HostileReference*> threatList = getThreatManager().getThreatList(); + std::list<HostileReference*> offlineThreatList = getThreatManager().getOfflineThreatList(); - // merge expects sorted lists - threatList.sort(); - offlineThreatList.sort(); - threatList.merge(offlineThreatList); + // merge expects sorted lists + threatList.sort(); + offlineThreatList.sort(); + threatList.merge(offlineThreatList); - for (std::list<HostileReference*>::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) - if (Unit* unit = (*itr)->getTarget()) - unit->getHostileRefManager().setOnlineOfflineState(ToCreature(), unit->InSamePhase(newPhaseMask)); - } + for (std::list<HostileReference*>::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + if (Unit* unit = (*itr)->getTarget()) + unit->getHostileRefManager().setOnlineOfflineState(ToCreature(), unit->IsInPhase(this)); } } - // Phase player, dont update - WorldObject::SetPhaseMask(newPhaseMask, false); - - // Phase pets and summons - if (IsInWorld()) - { - for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) - if ((*itr)->GetTypeId() == TYPEID_UNIT) - (*itr)->SetPhaseMask(newPhaseMask, true); - - for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i) - if (m_SummonSlot[i]) - if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i])) - summon->SetPhaseMask(newPhaseMask, true); - } + for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) + if ((*itr)->GetTypeId() == TYPEID_UNIT) + (*itr)->SetInPhase(id, true, apply); - // Update visibility after phasing pets and summons so they wont despawn - if (update) - UpdateObjectVisibility(); + for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i) + if (m_SummonSlot[i]) + if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i])) + summon->SetInPhase(id, true, apply); } void Unit::UpdateObjectVisibility(bool forced) @@ -16395,6 +14705,42 @@ void Unit::UpdateObjectVisibility(bool forced) } } +void Unit::SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin) +{ + ObjectGuid guid = GetGUID(); + WorldPacket data(SMSG_MOVE_KNOCK_BACK, (1+8+4+4+4+4+4)); + data.WriteBit(guid[0]); + data.WriteBit(guid[3]); + data.WriteBit(guid[6]); + data.WriteBit(guid[7]); + data.WriteBit(guid[2]); + data.WriteBit(guid[5]); + data.WriteBit(guid[1]); + data.WriteBit(guid[4]); + + data.WriteByteSeq(guid[1]); + + data << float(vsin); + data << uint32(0); + + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[7]); + + data << float(speedXY); + + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[3]); + + data << float(speedZ); + data << float(vcos); + + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[0]); + + player->GetSession()->SendPacket(&data); +} + void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ) { Player* player = ToPlayer(); @@ -16409,23 +14755,12 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ) } if (!player) - { GetMotionMaster()->MoveKnockbackFrom(x, y, speedXY, speedZ); - } else { float vcos, vsin; GetSinCos(x, y, vsin, vcos); - - WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); - data.append(GetPackGUID()); - data << uint32(0); // counter - data << float(vcos); // x direction - data << float(vsin); // y direction - data << float(speedXY); // Horizontal speed - data << float(-speedZ); // Z Movement speed (vertical) - - player->GetSession()->SendPacket(&data); + SendMoveKnockBack(player, speedXY, -speedZ, vcos, vsin); } } @@ -16475,6 +14810,72 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const return 892; } } + else if (getRace() == RACE_TROLL) + { + uint8 hairColor = GetByteValue(PLAYER_BYTES, 3); + switch (hairColor) + { + case 0: // Red + case 1: + return 33668; + case 2: // Yellow + case 3: + return 33667; + case 4: // Blue + case 5: + case 6: + return 33666; + case 7: // Purple + case 10: + return 33665; + default: // original - white + return 33669; + } + } + else if (getRace() == RACE_WORGEN) + { + // Based on Skin color + uint8 skinColor = GetByteValue(PLAYER_BYTES, 0); + // Male + if (getGender() == GENDER_MALE) + { + switch (skinColor) + { + case 1: // Brown + return 33662; + case 2: // Black + case 7: + return 33661; + case 4: // yellow + return 33664; + case 3: // White + case 5: + return 33663; + default: // original - Gray + return 33660; + } + } + // Female + else + { + switch (skinColor) + { + case 5: // Brown + case 6: + return 33662; + case 7: // Black + case 8: + return 33661; + case 3: // yellow + case 4: + return 33664; + case 2: // White + return 33663; + default: // original - Gray + return 33660; + } + } + } // Based on Skin color else if (getRace() == RACE_TAUREN) { @@ -16509,30 +14910,32 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const } } // Female - else switch (skinColor) + else { - case 10: // White - return 29409; - case 6: // Light Brown - case 7: - return 29410; - case 4: // Brown - case 5: - return 29411; - case 0: // Dark - case 1: - case 2: - case 3: - return 29412; - default: // original - Grey - return 8571; + switch (skinColor) + { + case 10: // White + return 29409; + case 6: // Light Brown + case 7: + return 29410; + case 4: // Brown + case 5: + return 29411; + case 0: // Dark + case 1: + case 2: + case 3: + return 29412; + default: // original - Grey + return 8571; + } } } else if (Player::TeamForRace(getRace()) == ALLIANCE) return 892; else return 8571; - case FORM_DIREBEAR: case FORM_BEAR: // Based on Hair color if (getRace() == RACE_NIGHTELF) @@ -16554,6 +14957,73 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const return 2281; } } + else if (getRace() == RACE_TROLL) + { + uint8 hairColor = GetByteValue(PLAYER_BYTES, 3); + switch (hairColor) + { + case 0: // Red + case 1: + return 33657; + case 2: // Yellow + case 3: + return 33659; + case 7: // Purple + case 10: + return 33656; + case 8: // White + case 9: + case 11: + case 12: + return 33658; + default: // original - Blue + return 33655; + } + } + else if (getRace() == RACE_WORGEN) + { + // Based on Skin color + uint8 skinColor = GetByteValue(PLAYER_BYTES, 0); + // Male + if (getGender() == GENDER_MALE) + { + switch (skinColor) + { + case 1: // Brown + return 33652; + case 2: // Black + case 7: + return 33651; + case 4: // Yellow + return 33653; + case 3: // White + case 5: + return 33654; + default: // original - Gray + return 33650; + } + } + // Female + else + { + switch (skinColor) + { + case 5: // Brown + case 6: + return 33652; + case 7: // Black + case 8: + return 33651; + case 3: // yellow + case 4: + return 33654; + case 2: // White + return 33653; + default: // original - Gray + return 33650; + } + } + } // Based on Skin color else if (getRace() == RACE_TAUREN) { @@ -16588,23 +15058,26 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const } } // Female - else switch (skinColor) + else { - case 0: // Dark (Black) - case 1: - return 29418; - case 2: // White - case 3: - return 29419; - case 6: // Light Brown/Grey - case 7: - case 8: - case 9: - return 29420; - case 10: // Completly White - return 29421; - default: // original - Brown - return 2289; + switch (skinColor) + { + case 0: // Dark (Black) + case 1: + return 29418; + case 2: // White + case 3: + return 29419; + case 6: // Light Brown/Grey + case 7: + case 8: + case 9: + return 29420; + case 10: // Completly White + return 29421; + default: // original - Brown + return 2289; + } } } else if (Player::TeamForRace(getRace()) == ALLIANCE) @@ -16617,15 +15090,25 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const return 20872; case FORM_FLIGHT_EPIC: if (Player::TeamForRace(getRace()) == ALLIANCE) - return 21243; + return (getRace() == RACE_WORGEN ? 37729 : 21243); + if (getRace() == RACE_TROLL) + return 37730; return 21244; + case FORM_MOONKIN: + if (getRace() == RACE_TROLL) + return 37174; + if (getRace() == RACE_WORGEN) + return 37173; + case FORM_GHOSTWOLF: + if (HasAura(58135)) //! Glyph of Arctic Wolf + return 27312; default: break; } } uint32 modelid = 0; - SpellShapeshiftEntry const* formEntry = sSpellShapeshiftStore.LookupEntry(form); + SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(form); if (formEntry && formEntry->modelID_A) { // Take the alliance modelid as default @@ -16726,6 +15209,21 @@ uint32 Unit::GetModelForTotem(PlayerTotemType totemType) } break; } + case RACE_GOBLIN: + { + switch (totemType) + { + case SUMMON_TYPE_TOTEM_FIRE: // fire + return 30783; + case SUMMON_TYPE_TOTEM_EARTH: // earth + return 30782; + case SUMMON_TYPE_TOTEM_WATER: // water + return 30784; + case SUMMON_TYPE_TOTEM_AIR: // air + return 30781; + } + break; + } } return 0; } @@ -16739,16 +15237,7 @@ void Unit::JumpTo(float speedXY, float speedZ, bool forward) { float vcos = std::cos(angle+GetOrientation()); float vsin = std::sin(angle+GetOrientation()); - - WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); - data.append(GetPackGUID()); - data << uint32(0); // Sequence - data << float(vcos); // x direction - data << float(vsin); // y direction - data << float(speedXY); // Horizontal speed - data << float(-speedZ); // Z Movement speed (vertical) - - ToPlayer()->GetSession()->SendPacket(&data); + SendMoveKnockBack(ToPlayer(), speedXY, -speedZ, vcos, vsin); } } @@ -16955,12 +15444,6 @@ void Unit::_ExitVehicle(Position const* exitPosition) if (player) player->SetFallInformation(0, GetPositionZ()); - else if (HasUnitMovementFlag(MOVEMENTFLAG_ROOT)) - { - WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, 8); - data.append(GetPackGUID()); - SendMessageToSet(&data, false); - } float height = pos.GetPositionZ(); @@ -16993,58 +15476,6 @@ void Unit::_ExitVehicle(Position const* exitPosition) } } -void Unit::BuildMovementPacket(ByteBuffer *data) const -{ - *data << uint32(GetUnitMovementFlags()); // movement flags - *data << uint16(GetExtraUnitMovementFlags()); // 2.3.0 - *data << uint32(getMSTime()); // time / counter - *data << GetPositionX(); - *data << GetPositionY(); - *data << GetPositionZMinusOffset(); - *data << GetOrientation(); - - // 0x00000200 - if (GetUnitMovementFlags() & MOVEMENTFLAG_ONTRANSPORT) - { - if (m_vehicle) - data->append(m_vehicle->GetBase()->GetPackGUID()); - else if (GetTransport()) - data->append(GetTransport()->GetPackGUID()); - else - *data << (uint8)0; - - *data << float (GetTransOffsetX()); - *data << float (GetTransOffsetY()); - *data << float (GetTransOffsetZ()); - *data << float (GetTransOffsetO()); - *data << uint32(GetTransTime()); - *data << uint8 (GetTransSeat()); - - if (GetExtraUnitMovementFlags() & MOVEMENTFLAG2_INTERPOLATED_MOVEMENT) - *data << uint32(m_movementInfo.transport.time2); - } - - // 0x02200000 - if ((GetUnitMovementFlags() & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) - || (m_movementInfo.flags2 & MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING)) - *data << (float)m_movementInfo.pitch; - - *data << (uint32)m_movementInfo.fallTime; - - // 0x00001000 - if (GetUnitMovementFlags() & MOVEMENTFLAG_FALLING) - { - *data << (float)m_movementInfo.jump.zspeed; - *data << (float)m_movementInfo.jump.sinAngle; - *data << (float)m_movementInfo.jump.cosAngle; - *data << (float)m_movementInfo.jump.xyspeed; - } - - // 0x04000000 - if (GetUnitMovementFlags() & MOVEMENTFLAG_SPLINE_ELEVATION) - *data << (float)m_movementInfo.splineElevation; -} - bool Unit::IsFalling() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING | MOVEMENTFLAG_FALLING_FAR) || movespline->isFalling(); @@ -17064,20 +15495,304 @@ void Unit::NearTeleportTo(float x, float y, float z, float orientation, bool cas } } +void Unit::WriteMovementInfo(WorldPacket& data, Movement::ExtraMovementStatusElement* extras /*= NULL*/) +{ + MovementInfo const& mi = m_movementInfo; + + bool hasMovementFlags = GetUnitMovementFlags() != 0; + bool hasMovementFlags2 = GetExtraUnitMovementFlags() != 0; + bool hasTimestamp = true; + bool hasOrientation = !G3D::fuzzyEq(GetOrientation(), 0.0f); + bool hasTransportData = GetTransGUID() != 0; + bool hasSpline = IsSplineEnabled(); + + bool hasTransportTime2 = hasTransportData && m_movementInfo.transport.time2 != 0; + bool hasTransportTime3 = false; + bool hasPitch = HasUnitMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || HasExtraUnitMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING); + bool hasFallDirection = HasUnitMovementFlag(MOVEMENTFLAG_FALLING); + bool hasFallData = hasFallDirection || m_movementInfo.jump.fallTime != 0; + bool hasSplineElevation = HasUnitMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION); + + MovementStatusElements const* sequence = GetMovementStatusElementsSequence(data.GetOpcode()); + if (!sequence) + { + TC_LOG_ERROR("network", "Unit::WriteMovementInfo: No movement sequence found for opcode %s", GetOpcodeNameForLogging(data.GetOpcode()).c_str()); + return; + } + + ObjectGuid guid = GetGUID(); + ObjectGuid tguid = hasTransportData ? GetTransGUID() : 0; + + for (; *sequence != MSEEnd; ++sequence) + { + MovementStatusElements const& element = *sequence; + + switch (element) + { + case MSEHasGuidByte0: + case MSEHasGuidByte1: + case MSEHasGuidByte2: + case MSEHasGuidByte3: + case MSEHasGuidByte4: + case MSEHasGuidByte5: + case MSEHasGuidByte6: + case MSEHasGuidByte7: + data.WriteBit(guid[element - MSEHasGuidByte0]); + break; + case MSEHasTransportGuidByte0: + case MSEHasTransportGuidByte1: + case MSEHasTransportGuidByte2: + case MSEHasTransportGuidByte3: + case MSEHasTransportGuidByte4: + case MSEHasTransportGuidByte5: + case MSEHasTransportGuidByte6: + case MSEHasTransportGuidByte7: + if (hasTransportData) + data.WriteBit(tguid[element - MSEHasTransportGuidByte0]); + break; + case MSEGuidByte0: + case MSEGuidByte1: + case MSEGuidByte2: + case MSEGuidByte3: + case MSEGuidByte4: + case MSEGuidByte5: + case MSEGuidByte6: + case MSEGuidByte7: + data.WriteByteSeq(guid[element - MSEGuidByte0]); + break; + case MSETransportGuidByte0: + case MSETransportGuidByte1: + case MSETransportGuidByte2: + case MSETransportGuidByte3: + case MSETransportGuidByte4: + case MSETransportGuidByte5: + case MSETransportGuidByte6: + case MSETransportGuidByte7: + if (hasTransportData) + data.WriteByteSeq(tguid[element - MSETransportGuidByte0]); + break; + case MSEHasMovementFlags: + data.WriteBit(!hasMovementFlags); + break; + case MSEHasMovementFlags2: + data.WriteBit(!hasMovementFlags2); + break; + case MSEHasTimestamp: + data.WriteBit(!hasTimestamp); + break; + case MSEHasOrientation: + data.WriteBit(!hasOrientation); + break; + case MSEHasTransportData: + data.WriteBit(hasTransportData); + break; + case MSEHasTransportTime2: + if (hasTransportData) + data.WriteBit(hasTransportTime2); + break; + case MSEHasTransportTime3: + if (hasTransportData) + data.WriteBit(hasTransportTime3); + break; + case MSEHasPitch: + data.WriteBit(!hasPitch); + break; + case MSEHasFallData: + data.WriteBit(hasFallData); + break; + case MSEHasFallDirection: + if (hasFallData) + data.WriteBit(hasFallDirection); + break; + case MSEHasSplineElevation: + data.WriteBit(!hasSplineElevation); + break; + case MSEHasSpline: + data.WriteBit(hasSpline); + break; + case MSEMovementFlags: + if (hasMovementFlags) + data.WriteBits(GetUnitMovementFlags(), 30); + break; + case MSEMovementFlags2: + if (hasMovementFlags2) + data.WriteBits(GetExtraUnitMovementFlags(), 12); + break; + case MSETimestamp: + if (hasTimestamp) + data << getMSTime(); + break; + case MSEPositionX: + data << GetPositionX(); + break; + case MSEPositionY: + data << GetPositionY(); + break; + case MSEPositionZ: + data << GetPositionZ(); + break; + case MSEOrientation: + if (hasOrientation) + data << GetOrientation(); + break; + case MSETransportPositionX: + if (hasTransportData) + data << GetTransOffsetX(); + break; + case MSETransportPositionY: + if (hasTransportData) + data << GetTransOffsetY(); + break; + case MSETransportPositionZ: + if (hasTransportData) + data << GetTransOffsetZ(); + break; + case MSETransportOrientation: + if (hasTransportData) + data << GetTransOffsetO(); + break; + case MSETransportSeat: + if (hasTransportData) + data << GetTransSeat(); + break; + case MSETransportTime: + if (hasTransportData) + data << GetTransTime(); + break; + case MSETransportTime2: + if (hasTransportData && hasTransportTime2) + data << mi.transport.time2; + break; + case MSETransportTime3: + if (hasTransportData && hasTransportTime3) + data << mi.transport.time3; + break; + case MSEPitch: + if (hasPitch) + data << mi.pitch; + break; + case MSEFallTime: + if (hasFallData) + data << mi.jump.fallTime; + break; + case MSEFallVerticalSpeed: + if (hasFallData) + data << mi.jump.zspeed; + break; + case MSEFallCosAngle: + if (hasFallData && hasFallDirection) + data << mi.jump.cosAngle; + break; + case MSEFallSinAngle: + if (hasFallData && hasFallDirection) + data << mi.jump.sinAngle; + break; + case MSEFallHorizontalSpeed: + if (hasFallData && hasFallDirection) + data << mi.jump.xyspeed; + break; + case MSESplineElevation: + if (hasSplineElevation) + data << mi.splineElevation; + break; + case MSECounter: + data << m_movementCounter++; + break; + case MSEZeroBit: + data.WriteBit(0); + break; + case MSEOneBit: + data.WriteBit(1); + break; + case MSEExtraElement: + extras->WriteNextElement(data); + break; + default: + ASSERT(Movement::PrintInvalidSequenceElement(element, __FUNCTION__)); + break; + } + } +} + void Unit::SendTeleportPacket(Position& pos) { - Position oldPos = { GetPositionX(), GetPositionY(), GetPositionZMinusOffset(), GetOrientation() }; - if (GetTypeId() == TYPEID_UNIT) - Relocate(&pos); + // SMSG_MOVE_UPDATE_TELEPORT is sent to nearby players to signal the teleport + // MSG_MOVE_TELEPORT is sent to self in order to trigger MSG_MOVE_TELEPORT_ACK and update the position server side + + // This oldPos actually contains the destination position if the Unit is a Player. + Position oldPos = {GetPositionX(), GetPositionY(), GetPositionZMinusOffset(), GetOrientation()}; - WorldPacket data2(MSG_MOVE_TELEPORT, 38); - data2.append(GetPackGUID()); - BuildMovementPacket(&data2); if (GetTypeId() == TYPEID_UNIT) - Relocate(&oldPos); + Relocate(&pos); // Relocate the unit to its new position in order to build the packets correctly. + + ObjectGuid guid = GetGUID(); + ObjectGuid transGuid = GetTransGUID(); + + WorldPacket data(SMSG_MOVE_UPDATE_TELEPORT, 38); + WriteMovementInfo(data); + + if (GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data2(MSG_MOVE_TELEPORT, 38); + data2.WriteBit(guid[6]); + data2.WriteBit(guid[0]); + data2.WriteBit(guid[3]); + data2.WriteBit(guid[2]); + data2.WriteBit(0); // unknown + data2.WriteBit(uint64(transGuid)); + data2.WriteBit(guid[1]); + if (transGuid) + { + data2.WriteBit(transGuid[1]); + data2.WriteBit(transGuid[3]); + data2.WriteBit(transGuid[2]); + data2.WriteBit(transGuid[5]); + data2.WriteBit(transGuid[0]); + data2.WriteBit(transGuid[7]); + data2.WriteBit(transGuid[6]); + data2.WriteBit(transGuid[4]); + } + data2.WriteBit(guid[4]); + data2.WriteBit(guid[7]); + data2.WriteBit(guid[5]); + data2.FlushBits(); + + if (transGuid) + { + data2.WriteByteSeq(transGuid[6]); + data2.WriteByteSeq(transGuid[5]); + data2.WriteByteSeq(transGuid[1]); + data2.WriteByteSeq(transGuid[7]); + data2.WriteByteSeq(transGuid[0]); + data2.WriteByteSeq(transGuid[2]); + data2.WriteByteSeq(transGuid[4]); + data2.WriteByteSeq(transGuid[3]); + } + + data2 << uint32(0); // counter + data2.WriteByteSeq(guid[1]); + data2.WriteByteSeq(guid[2]); + data2.WriteByteSeq(guid[3]); + data2.WriteByteSeq(guid[5]); + data2 << float(GetPositionX()); + data2.WriteByteSeq(guid[4]); + data2 << float(GetOrientation()); + data2.WriteByteSeq(guid[7]); + data2 << float(GetPositionZMinusOffset()); + data2.WriteByteSeq(guid[0]); + data2.WriteByteSeq(guid[6]); + data2 << float(GetPositionY()); + ToPlayer()->SendDirectMessage(&data2); // Send the MSG_MOVE_TELEPORT packet to self. + } + + // Relocate the player/creature to its old position, so we can broadcast to nearby players correctly if (GetTypeId() == TYPEID_PLAYER) Relocate(&pos); - SendMessageToSet(&data2, false); + else + Relocate(&oldPos); + + // Broadcast the packet to everyone except self. + SendMessageToSet(&data, false); } bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport) @@ -17143,7 +15858,7 @@ void Unit::SendThreatListUpdate() { uint32 count = getThreatManager().getThreatList().size(); - //TC_LOG_DEBUG("entities.unit", "WORLD: Send SMSG_THREAT_UPDATE Message"); + TC_LOG_DEBUG("entities.unit", "WORLD: Send SMSG_THREAT_UPDATE Message"); WorldPacket data(SMSG_THREAT_UPDATE, 8 + count * 8); data.append(GetPackGUID()); data << uint32(count); @@ -17195,27 +15910,22 @@ void Unit::SendRemoveFromThreatListOpcode(HostileReference* pHostileReference) SendMessageToSet(&data, false); } -void Unit::RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker) +// baseRage means damage taken when attacker = false +void Unit::RewardRage(uint32 baseRage, bool attacker) { float addRage; - float rageconversion = ((0.0091107836f * getLevel() * getLevel()) + 3.225598133f * getLevel()) + 4.2652911f; - - // Unknown if correct, but lineary adjust rage conversion above level 70 - if (getLevel() > 70) - rageconversion += 13.27f * (getLevel() - 70); - if (attacker) { - addRage = (damage / rageconversion * 7.5f + weaponSpeedHitFactor) / 2; - + addRage = baseRage; // talent who gave more rage on attack AddPct(addRage, GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT)); } else { - addRage = damage / rageconversion * 2.5f; - + // Calculate rage from health and damage taken + //! ToDo: Check formula + addRage = floor(0.5f + (25.7f * baseRage / GetMaxHealth())); // Berserker Rage effect if (HasAura(18499)) addRage *= 2.0f; @@ -17416,7 +16126,7 @@ void Unit::SetFacingTo(float ori) { Movement::MoveSplineInit init(this); init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset(), false); - if (HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && GetTransGUID()) + if (GetTransport()) init.DisableTransportPathTransformations(); // It makes no sense to target global orientation init.SetFacing(ori); init.Launch(); @@ -17445,28 +16155,56 @@ bool Unit::SetWalk(bool enable) else RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + ///@ TODO: Find proper opcode for walk mode setting in player mind controlling a player case + if (enable) + Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_WALK_MODE, SMSG_SPLINE_MOVE_SET_WALK_MODE).Send(); + else + Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_RUN_MODE, SMSG_SPLINE_MOVE_SET_RUN_MODE).Send(); + return true; } -bool Unit::SetDisableGravity(bool disable, bool /*packetOnly = false*/) +bool Unit::SetDisableGravity(bool disable, bool packetOnly /*= false*/) { - if (disable == IsLevitating()) - return false; - - if (disable) + if (!packetOnly) { - AddUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY); - RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING); + if (disable == IsLevitating()) + return false; + + if (disable) + { + AddUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY); + RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_SPLINE_ELEVATION); + SetFall(false); + } + else + { + RemoveUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY); + if (!HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY)) + SetFall(true); + } } + + if (disable) + Movement::PacketSender(this, SMSG_SPLINE_MOVE_GRAVITY_DISABLE, SMSG_MOVE_GRAVITY_DISABLE).Send(); else + Movement::PacketSender(this, SMSG_SPLINE_MOVE_GRAVITY_ENABLE, SMSG_MOVE_GRAVITY_ENABLE).Send(); + + return true; +} + +bool Unit::SetFall(bool enable) +{ + if (enable == HasUnitMovementFlag(MOVEMENTFLAG_FALLING)) + return false; + + if (enable) { - RemoveUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY); - if (!HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY)) - { - m_movementInfo.SetFallTime(0); - AddUnitMovementFlag(MOVEMENTFLAG_FALLING); - } + AddUnitMovementFlag(MOVEMENTFLAG_FALLING); + m_movementInfo.SetFallTime(0); } + else + RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING | MOVEMENTFLAG_FALLING_FAR); return true; } @@ -17481,6 +16219,11 @@ bool Unit::SetSwim(bool enable) else RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING); + if (enable) + Movement::PacketSender(this, SMSG_SPLINE_MOVE_START_SWIM, NULL_OPCODE).Send(); + else + Movement::PacketSender(this, SMSG_SPLINE_MOVE_STOP_SWIM, NULL_OPCODE).Send(); + return true; } @@ -17492,90 +16235,161 @@ bool Unit::SetCanFly(bool enable) if (enable) { AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY); - RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING); + RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_SPLINE_ELEVATION); + SetFall(false); } else { RemoveUnitMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_MASK_MOVING_FLY); if (!IsLevitating()) - { - m_movementInfo.SetFallTime(0); - AddUnitMovementFlag(MOVEMENTFLAG_FALLING); - } + SetFall(true); } + if (enable) + Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_FLYING, SMSG_MOVE_SET_CAN_FLY).Send(); + else + Movement::PacketSender(this, SMSG_SPLINE_MOVE_UNSET_FLYING, SMSG_MOVE_UNSET_CAN_FLY).Send(); + return true; } -bool Unit::SetWaterWalking(bool enable, bool /*packetOnly = false */) +bool Unit::SetWaterWalking(bool enable, bool packetOnly /*= false */) { - if (enable == HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING)) - return false; + if (!packetOnly) + { + if (enable == HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING)) + return false; + + if (enable) + AddUnitMovementFlag(MOVEMENTFLAG_WATERWALKING); + else + RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING); + } if (enable) - AddUnitMovementFlag(MOVEMENTFLAG_WATERWALKING); + Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_WATER_WALK, SMSG_MOVE_WATER_WALK).Send(); else - RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING); + Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_LAND_WALK, SMSG_MOVE_LAND_WALK).Send(); return true; } -bool Unit::SetFeatherFall(bool enable, bool /*packetOnly = false */) +bool Unit::SetFeatherFall(bool enable, bool packetOnly /*= false */) { - if (enable == HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW)) - return false; + if (!packetOnly) + { + if (enable == HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW)) + return false; + + if (enable) + AddUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW); + else + RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW); + } if (enable) - AddUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW); + Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_FEATHER_FALL, SMSG_MOVE_FEATHER_FALL).Send(); else - RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW); + Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_NORMAL_FALL, SMSG_MOVE_NORMAL_FALL).Send(); return true; } -bool Unit::SetHover(bool enable, bool /*packetOnly = false*/) +bool Unit::SetHover(bool enable, bool packetOnly /*= false*/) { - if (enable == HasUnitMovementFlag(MOVEMENTFLAG_HOVER)) - return false; + if (!packetOnly) + { + if (enable == HasUnitMovementFlag(MOVEMENTFLAG_HOVER)) + return false; - float hoverHeight = GetFloatValue(UNIT_FIELD_HOVERHEIGHT); + float hoverHeight = GetFloatValue(UNIT_FIELD_HOVERHEIGHT); - if (enable) - { - //! No need to check height on ascent - AddUnitMovementFlag(MOVEMENTFLAG_HOVER); - if (hoverHeight) - UpdateHeight(GetPositionZ() + hoverHeight); - } - else - { - RemoveUnitMovementFlag(MOVEMENTFLAG_HOVER); - if (hoverHeight) + if (enable) { - float newZ = GetPositionZ() - hoverHeight; - UpdateAllowedPositionZ(GetPositionX(), GetPositionY(), newZ); - UpdateHeight(newZ); + //! No need to check height on ascent + AddUnitMovementFlag(MOVEMENTFLAG_HOVER); + if (hoverHeight) + UpdateHeight(GetPositionZ() + hoverHeight); + } + else + { + RemoveUnitMovementFlag(MOVEMENTFLAG_HOVER); + if (hoverHeight) + { + float newZ = GetPositionZ() - hoverHeight; + UpdateAllowedPositionZ(GetPositionX(), GetPositionY(), newZ); + UpdateHeight(newZ); + } } } + if (enable) + Movement::PacketSender(this, SMSG_SPLINE_MOVE_SET_HOVER, SMSG_MOVE_SET_HOVER).Send(); + else + Movement::PacketSender(this, SMSG_SPLINE_MOVE_UNSET_HOVER, SMSG_MOVE_UNSET_HOVER).Send(); + return true; } +void Unit::SendSetPlayHoverAnim(bool enable) +{ + ObjectGuid guid = GetGUID(); + WorldPacket data(SMSG_SET_PLAY_HOVER_ANIM, 10); + data.WriteBit(guid[4]); + data.WriteBit(guid[0]); + data.WriteBit(guid[1]); + data.WriteBit(enable); + data.WriteBit(guid[3]); + data.WriteBit(guid[7]); + data.WriteBit(guid[5]); + data.WriteBit(guid[2]); + data.WriteBit(guid[6]); + + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[6]); + + SendMessageToSet(&data, true); +} + +void Unit::SendMovementSetSplineAnim(Movement::AnimType anim) +{ + WorldPacket data(SMSG_SPLINE_MOVE_SET_ANIM, 8 + 4); + data.append(GetPackGUID()); + data << uint32(anim); + SendMessageToSet(&data, false); +} + +bool Unit::IsSplineEnabled() const +{ + return movespline->Initialized() && !movespline->Finalized(); +} + + void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const { if (!target) return; ByteBuffer fieldBuffer; - UpdateMask updateMask; - updateMask.SetCount(m_valuesCount); + + uint32 valCount = m_valuesCount; uint32* flags = UnitUpdateFieldFlags; uint32 visibleFlag = UF_FLAG_PUBLIC; if (target == this) visibleFlag |= UF_FLAG_PRIVATE; + else if (GetTypeId() == TYPEID_PLAYER) + valCount = PLAYER_END_NOT_SELF; + + updateMask.SetCount(valCount); Player* plr = GetCharmerOrOwnerPlayerOrPlayerItself(); if (GetOwnerGUID() == target->GetGUID()) @@ -17589,7 +16403,7 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) visibleFlag |= UF_FLAG_PARTY_MEMBER; Creature const* creature = ToCreature(); - for (uint16 index = 0; index < m_valuesCount; ++index) + for (uint16 index = 0; index < valCount; ++index) { if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index e87eb957de8..035c3a6aa0e 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -28,6 +28,7 @@ #include "Object.h" #include "SpellAuraDefines.h" #include "ThreatManager.h" +#include "MoveSplineInit.h" #define WORLD_TRIGGER 12999 @@ -210,7 +211,7 @@ enum ShapeshiftForm FORM_BEAR = 0x05, FORM_AMBIENT = 0x06, FORM_GHOUL = 0x07, - FORM_DIREBEAR = 0x08, + FORM_DIREBEAR = 0x08, // Removed in 4.0.1 FORM_STEVES_GHOUL = 0x09, FORM_THARONJA_SKELETON = 0x0A, FORM_TEST_OF_STRENGTH = 0x0B, @@ -354,6 +355,11 @@ class Vehicle; class VehicleJoinEvent; class TransportBase; class SpellCastTargets; +namespace Movement +{ + class ExtraMovementStatusElement; + class MoveSpline; +} typedef std::list<Unit*> UnitList; typedef std::list< std::pair<Aura*, uint8> > DispelChargesList; @@ -418,6 +424,7 @@ enum TriggerCastFlags TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default) TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements + TRIGGERED_IGNORE_TARGET_CHECK = 0x00100000, //! Will ignore most target checks (mostly DBC target checks) TRIGGERED_FULL_MASK = 0xFFFFFFFF }; @@ -433,9 +440,13 @@ enum UnitMods UNIT_MOD_RAGE, UNIT_MOD_FOCUS, UNIT_MOD_ENERGY, - UNIT_MOD_HAPPINESS, + UNIT_MOD_UNUSED, // Old UNIT_MOD_HAPPINESS UNIT_MOD_RUNE, UNIT_MOD_RUNIC_POWER, + UNIT_MOD_SOUL_SHARDS, + UNIT_MOD_ECLIPSE, + UNIT_MOD_HOLY_POWER, + UNIT_MOD_ALTERNATIVE, UNIT_MOD_ARMOR, // UNIT_MOD_ARMOR..UNIT_MOD_RESISTANCE_ARCANE must be in existed order, it's accessed by index values of SpellSchools enum. UNIT_MOD_RESISTANCE_HOLY, UNIT_MOD_RESISTANCE_FIRE, @@ -455,7 +466,7 @@ enum UnitMods UNIT_MOD_RESISTANCE_START = UNIT_MOD_ARMOR, UNIT_MOD_RESISTANCE_END = UNIT_MOD_RESISTANCE_ARCANE + 1, UNIT_MOD_POWER_START = UNIT_MOD_MANA, - UNIT_MOD_POWER_END = UNIT_MOD_RUNIC_POWER + 1 + UNIT_MOD_POWER_END = UNIT_MOD_ALTERNATIVE + 1 }; enum BaseModGroup @@ -560,34 +571,35 @@ enum WeaponAttackType enum CombatRating { - CR_WEAPON_SKILL = 0, - CR_DEFENSE_SKILL = 1, - CR_DODGE = 2, - CR_PARRY = 3, - CR_BLOCK = 4, - CR_HIT_MELEE = 5, - CR_HIT_RANGED = 6, - CR_HIT_SPELL = 7, - CR_CRIT_MELEE = 8, - CR_CRIT_RANGED = 9, - CR_CRIT_SPELL = 10, - CR_HIT_TAKEN_MELEE = 11, - CR_HIT_TAKEN_RANGED = 12, - CR_HIT_TAKEN_SPELL = 13, - CR_CRIT_TAKEN_MELEE = 14, - CR_CRIT_TAKEN_RANGED = 15, - CR_CRIT_TAKEN_SPELL = 16, - CR_HASTE_MELEE = 17, - CR_HASTE_RANGED = 18, - CR_HASTE_SPELL = 19, - CR_WEAPON_SKILL_MAINHAND = 20, - CR_WEAPON_SKILL_OFFHAND = 21, - CR_WEAPON_SKILL_RANGED = 22, - CR_EXPERTISE = 23, - CR_ARMOR_PENETRATION = 24 -}; - -#define MAX_COMBAT_RATING 25 + CR_WEAPON_SKILL = 0, + CR_DEFENSE_SKILL = 1, // Removed in 4.0.1 + CR_DODGE = 2, + CR_PARRY = 3, + CR_BLOCK = 4, + CR_HIT_MELEE = 5, + CR_HIT_RANGED = 6, + CR_HIT_SPELL = 7, + CR_CRIT_MELEE = 8, + CR_CRIT_RANGED = 9, + CR_CRIT_SPELL = 10, + CR_HIT_TAKEN_MELEE = 11, // Deprecated since Cataclysm + CR_HIT_TAKEN_RANGED = 12, // Deprecated since Cataclysm + CR_HIT_TAKEN_SPELL = 13, // Deprecated since Cataclysm + CR_RESILIENCE_CRIT_TAKEN = 14, + CR_RESILIENCE_PLAYER_DAMAGE_TAKEN = 15, + CR_CRIT_TAKEN_SPELL = 16, // Deprecated since Cataclysm + CR_HASTE_MELEE = 17, + CR_HASTE_RANGED = 18, + CR_HASTE_SPELL = 19, + CR_WEAPON_SKILL_MAINHAND = 20, + CR_WEAPON_SKILL_OFFHAND = 21, + CR_WEAPON_SKILL_RANGED = 22, + CR_EXPERTISE = 23, + CR_ARMOR_PENETRATION = 24, + CR_MASTERY = 25, +}; + +#define MAX_COMBAT_RATING 26 enum DamageEffectType { @@ -665,7 +677,7 @@ enum NPCFlags { UNIT_NPC_FLAG_NONE = 0x00000000, UNIT_NPC_FLAG_GOSSIP = 0x00000001, // 100% - UNIT_NPC_FLAG_QUESTGIVER = 0x00000002, // guessed, probably ok + UNIT_NPC_FLAG_QUESTGIVER = 0x00000002, // 100% UNIT_NPC_FLAG_UNK1 = 0x00000004, UNIT_NPC_FLAG_UNK2 = 0x00000008, UNIT_NPC_FLAG_TRAINER = 0x00000010, // 100% @@ -690,7 +702,10 @@ enum NPCFlags UNIT_NPC_FLAG_GUILD_BANKER = 0x00800000, // cause client to send 997 opcode UNIT_NPC_FLAG_SPELLCLICK = 0x01000000, // cause client to send 1015 opcode (spell click) UNIT_NPC_FLAG_PLAYER_VEHICLE = 0x02000000, // players with mounts that have vehicle data should have it set - UNIT_NPC_FLAG_MAILBOX = 0x04000000 // + UNIT_NPC_FLAG_MAILBOX = 0x04000000, // mailbox + UNIT_NPC_FLAG_REFORGER = 0x08000000, // reforging + UNIT_NPC_FLAG_TRANSMOGRIFIER = 0x10000000, // transmogrification + UNIT_NPC_FLAG_VAULTKEEPER = 0x20000000 // void storage }; enum MovementFlags @@ -705,28 +720,27 @@ enum MovementFlags MOVEMENTFLAG_PITCH_UP = 0x00000040, MOVEMENTFLAG_PITCH_DOWN = 0x00000080, MOVEMENTFLAG_WALKING = 0x00000100, // Walking - MOVEMENTFLAG_ONTRANSPORT = 0x00000200, // Used for flying on some creatures - MOVEMENTFLAG_DISABLE_GRAVITY = 0x00000400, // Former MOVEMENTFLAG_LEVITATING. This is used when walking is not possible. - MOVEMENTFLAG_ROOT = 0x00000800, // Must not be set along with MOVEMENTFLAG_MASK_MOVING - MOVEMENTFLAG_FALLING = 0x00001000, // damage dealt on that type of falling - MOVEMENTFLAG_FALLING_FAR = 0x00002000, - MOVEMENTFLAG_PENDING_STOP = 0x00004000, - MOVEMENTFLAG_PENDING_STRAFE_STOP = 0x00008000, - MOVEMENTFLAG_PENDING_FORWARD = 0x00010000, - MOVEMENTFLAG_PENDING_BACKWARD = 0x00020000, - MOVEMENTFLAG_PENDING_STRAFE_LEFT = 0x00040000, - MOVEMENTFLAG_PENDING_STRAFE_RIGHT = 0x00080000, - MOVEMENTFLAG_PENDING_ROOT = 0x00100000, - MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also - MOVEMENTFLAG_ASCENDING = 0x00400000, // press "space" when flying - MOVEMENTFLAG_DESCENDING = 0x00800000, - MOVEMENTFLAG_CAN_FLY = 0x01000000, // Appears when unit can fly AND also walk - MOVEMENTFLAG_FLYING = 0x02000000, // unit is actually flying. pretty sure this is only used for players. creatures use disable_gravity - MOVEMENTFLAG_SPLINE_ELEVATION = 0x04000000, // used for flight paths - MOVEMENTFLAG_SPLINE_ENABLED = 0x08000000, // used for flight paths - MOVEMENTFLAG_WATERWALKING = 0x10000000, // prevent unit from falling through water - MOVEMENTFLAG_FALLING_SLOW = 0x20000000, // active rogue safe fall spell (passive) - MOVEMENTFLAG_HOVER = 0x40000000, // hover, cannot jump + MOVEMENTFLAG_DISABLE_GRAVITY = 0x00000200, // Former MOVEMENTFLAG_LEVITATING. This is used when walking is not possible. + MOVEMENTFLAG_ROOT = 0x00000400, // Must not be set along with MOVEMENTFLAG_MASK_MOVING + MOVEMENTFLAG_FALLING = 0x00000800, // damage dealt on that type of falling + MOVEMENTFLAG_FALLING_FAR = 0x00001000, + MOVEMENTFLAG_PENDING_STOP = 0x00002000, + MOVEMENTFLAG_PENDING_STRAFE_STOP = 0x00004000, + MOVEMENTFLAG_PENDING_FORWARD = 0x00008000, + MOVEMENTFLAG_PENDING_BACKWARD = 0x00010000, + MOVEMENTFLAG_PENDING_STRAFE_LEFT = 0x00020000, + MOVEMENTFLAG_PENDING_STRAFE_RIGHT = 0x00040000, + MOVEMENTFLAG_PENDING_ROOT = 0x00080000, + MOVEMENTFLAG_SWIMMING = 0x00100000, // appears with fly flag also + MOVEMENTFLAG_ASCENDING = 0x00200000, // press "space" when flying + MOVEMENTFLAG_DESCENDING = 0x00400000, + MOVEMENTFLAG_CAN_FLY = 0x00800000, // Appears when unit can fly AND also walk + MOVEMENTFLAG_FLYING = 0x01000000, // unit is actually flying. pretty sure this is only used for players. creatures use disable_gravity + MOVEMENTFLAG_SPLINE_ELEVATION = 0x02000000, // used for flight paths + MOVEMENTFLAG_WATERWALKING = 0x04000000, // prevent unit from falling through water + MOVEMENTFLAG_FALLING_SLOW = 0x08000000, // active rogue safe fall spell (passive) + MOVEMENTFLAG_HOVER = 0x10000000, // hover, cannot jump + MOVEMENTFLAG_DISABLE_COLLISION = 0x20000000, /// @todo Check if PITCH_UP and PITCH_DOWN really belong here.. MOVEMENTFLAG_MASK_MOVING = @@ -740,6 +754,12 @@ enum MovementFlags MOVEMENTFLAG_MASK_MOVING_FLY = MOVEMENTFLAG_FLYING | MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING, + // Movement flags allowed for creature in CreateObject - we need to keep all other enabled serverside + // to properly calculate all movement + MOVEMENTFLAG_MASK_CREATURE_ALLOWED = + MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_DISABLE_GRAVITY | MOVEMENTFLAG_ROOT | MOVEMENTFLAG_SWIMMING | + MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_WATERWALKING | MOVEMENTFLAG_FALLING_SLOW | MOVEMENTFLAG_HOVER, + /// @todo if needed: add more flags to this masks that are exclusive to players MOVEMENTFLAG_MASK_PLAYER_ONLY = MOVEMENTFLAG_FLYING, @@ -754,20 +774,20 @@ enum MovementFlags2 MOVEMENTFLAG2_NONE = 0x00000000, MOVEMENTFLAG2_NO_STRAFE = 0x00000001, MOVEMENTFLAG2_NO_JUMPING = 0x00000002, - MOVEMENTFLAG2_UNK3 = 0x00000004, // Overrides various clientside checks - MOVEMENTFLAG2_FULL_SPEED_TURNING = 0x00000008, - MOVEMENTFLAG2_FULL_SPEED_PITCHING = 0x00000010, - MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING = 0x00000020, - MOVEMENTFLAG2_UNK7 = 0x00000040, - MOVEMENTFLAG2_UNK8 = 0x00000080, - MOVEMENTFLAG2_UNK9 = 0x00000100, - MOVEMENTFLAG2_UNK10 = 0x00000200, - MOVEMENTFLAG2_INTERPOLATED_MOVEMENT = 0x00000400, - MOVEMENTFLAG2_INTERPOLATED_TURNING = 0x00000800, - MOVEMENTFLAG2_INTERPOLATED_PITCHING = 0x00001000, - MOVEMENTFLAG2_UNK14 = 0x00002000, - MOVEMENTFLAG2_UNK15 = 0x00004000, - MOVEMENTFLAG2_UNK16 = 0x00008000 + MOVEMENTFLAG2_FULL_SPEED_TURNING = 0x00000004, + MOVEMENTFLAG2_FULL_SPEED_PITCHING = 0x00000008, + MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING = 0x00000010, + MOVEMENTFLAG2_UNK5 = 0x00000020, + MOVEMENTFLAG2_UNK6 = 0x00000040, + MOVEMENTFLAG2_UNK7 = 0x00000080, + MOVEMENTFLAG2_UNK8 = 0x00000100, + MOVEMENTFLAG2_UNK9 = 0x00000200, + MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS = 0x00000400, + MOVEMENTFLAG2_UNK11 = 0x00000800, + MOVEMENTFLAG2_UNK12 = 0x00001000, + MOVEMENTFLAG2_INTERPOLATED_MOVEMENT = 0x00002000, + MOVEMENTFLAG2_INTERPOLATED_TURNING = 0x00004000, + MOVEMENTFLAG2_INTERPOLATED_PITCHING = 0x00008000 }; enum UnitTypeMask @@ -785,10 +805,6 @@ enum UnitTypeMask UNIT_MASK_ACCESSORY = 0x00000200 }; -namespace Movement{ - class MoveSpline; -} - struct DiminishingReturn { DiminishingReturn(DiminishingGroup group, uint32 t, uint32 count) @@ -1078,7 +1094,8 @@ enum CommandStates COMMAND_STAY = 0, COMMAND_FOLLOW = 1, COMMAND_ATTACK = 2, - COMMAND_ABANDON = 3 + COMMAND_ABANDON = 3, + COMMAND_MOVE_TO = 4 }; #define UNIT_ACTION_BUTTON_ACTION(X) (uint32(X) & 0x00FFFFFF) @@ -1394,10 +1411,12 @@ class Unit : public WorldObject Powers getPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, 3)); } void setPowerType(Powers power); - uint32 GetPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_POWER1 +power); } - uint32 GetMaxPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_MAXPOWER1+power); } - void SetPower(Powers power, uint32 val); - void SetMaxPower(Powers power, uint32 val); + int32 GetPower(Powers power) const; + int32 GetMinPower(Powers power) const { return power == POWER_ECLIPSE ? -100 : 0; } + int32 GetMaxPower(Powers power) const; + int32 CountPctFromMaxPower(Powers power, int32 pct) const { return CalculatePct(GetMaxPower(power), pct); } + void SetPower(Powers power, int32 val); + void SetMaxPower(Powers power, int32 val); // returns the change in power int32 ModifyPower(Powers power, int32 val); int32 ModifyPowerPct(Powers power, float pct, bool apply = true); @@ -1444,6 +1463,10 @@ class Unit : public WorldObject uint32 GetMountID() const { return GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID); } void Mount(uint32 mount, uint32 vehicleId = 0, uint32 creatureEntry = 0); void Dismount(); + MountCapabilityEntry const* GetMountCapability(uint32 mountType) const; + + void SendDurabilityLoss(Player* receiver, uint32 percent); + void PlayOneShotAnimKit(uint32 id); uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } void DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb); @@ -1473,23 +1496,11 @@ class Unit : public WorldObject void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss); // player or player's pet resilience (-1%) - float GetMeleeCritChanceReduction() const { return GetCombatRatingReduction(CR_CRIT_TAKEN_MELEE); } - float GetRangedCritChanceReduction() const { return GetCombatRatingReduction(CR_CRIT_TAKEN_RANGED); } - float GetSpellCritChanceReduction() const { return GetCombatRatingReduction(CR_CRIT_TAKEN_SPELL); } - - // player or player's pet resilience (-1%) - uint32 GetMeleeCritDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_MELEE, 2.2f, 33.0f, damage); } - uint32 GetRangedCritDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_RANGED, 2.2f, 33.0f, damage); } - uint32 GetSpellCritDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_SPELL, 2.2f, 33.0f, damage); } + uint32 GetDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN, 1.0f, 100.0f, damage); } - // player or player's pet resilience (-1%), cap 100% - uint32 GetMeleeDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_MELEE, 2.0f, 100.0f, damage); } - uint32 GetRangedDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_RANGED, 2.0f, 100.0f, damage); } - uint32 GetSpellDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_SPELL, 2.0f, 100.0f, damage); } + void ApplyResilience(Unit const* victim, int32* damage) const; - void ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type) const; - - float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const; + float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, uint32 spellId) const; SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo); SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo); SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect = false); @@ -1502,11 +1513,10 @@ class Unit : public WorldObject int32 GetMechanicResistChance(SpellInfo const* spellInfo) const; bool CanUseAttackType(uint8 attacktype) const; - virtual uint32 GetShieldBlockValue() const =0; - uint32 GetShieldBlockValue(uint32 soft_cap, uint32 hard_cap) const; + virtual uint32 GetBlockPercent() const { return 30; } + uint32 GetUnitMeleeSkill(Unit const* target = NULL) const; - uint32 GetDefenseSkillValue(Unit const* target = NULL) const; - uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const; + float GetWeaponProcChance() const; float GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellInfo* spellProto) const; @@ -1567,7 +1577,7 @@ class Unit : public WorldObject void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false); int32 HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical = false); - void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, Powers powerType); + void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, Powers powertype); void EnergizeBySpell(Unit* victim, uint32 SpellID, int32 Damage, Powers powertype); uint32 SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage); @@ -1585,8 +1595,7 @@ class Unit : public WorldObject Aura* AddAura(uint32 spellId, Unit* target); Aura* AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target); void SetAuraStack(uint32 spellId, Unit* target, uint32 stack); - void SendPlaySpellVisual(uint32 id); - void SendPlaySpellImpact(uint64 guid, uint32 id); + void SendPlaySpellVisualKit(uint32 id, uint32 unkParam); void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown); void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns); @@ -1609,24 +1618,27 @@ class Unit : public WorldObject void UpdateOrientation(float orientation); void UpdateHeight(float newZ); + void SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin); void KnockbackFrom(float x, float y, float speedXY, float speedZ); void JumpTo(float speedXY, float speedZ, bool forward = true); void JumpTo(WorldObject* obj, float speedZ); void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath = false, bool forceDestination = false); - //void SetFacing(float ori, WorldObject* obj = NULL); - //void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); - void SendMovementFlagUpdate(bool self = false); + + + void SendSetPlayHoverAnim(bool enable); + void SendMovementSetSplineAnim(Movement::AnimType anim); bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY); } bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING); } - virtual bool SetWalk(bool enable); - virtual bool SetDisableGravity(bool disable, bool packetOnly = false); - virtual bool SetSwim(bool enable); - virtual bool SetCanFly(bool enable); - virtual bool SetWaterWalking(bool enable, bool packetOnly = false); - virtual bool SetFeatherFall(bool enable, bool packetOnly = false); - virtual bool SetHover(bool enable, bool packetOnly = false); + bool SetWalk(bool enable); + bool SetDisableGravity(bool disable, bool packetOnly = false); + bool SetFall(bool enable); + bool SetSwim(bool enable); + bool SetCanFly(bool enable); + bool SetWaterWalking(bool enable, bool packetOnly = false); + bool SetFeatherFall(bool enable, bool packetOnly = false); + bool SetHover(bool enable, bool packetOnly = false); void SetInFront(WorldObject const* target); void SetFacingTo(float ori); @@ -1639,8 +1651,6 @@ class Unit : public WorldObject void SendClearTarget(); - void BuildHeartBeatMsg(WorldPacket* data) const; - bool IsAlive() const { return (m_deathState == ALIVE); } bool isDying() const { return (m_deathState == JUST_DIED); } bool isDead() const { return (m_deathState == DEAD || m_deathState == CORPSE); } @@ -1752,7 +1762,7 @@ class Unit : public WorldObject void RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit* stealer); void RemoveAurasDueToItemSpell(uint32 spellId, uint64 castItemGuid); void RemoveAurasByType(AuraType auraType, uint64 casterGUID = 0, Aura* except = NULL, bool negative = true, bool positive = true); - void RemoveNotOwnSingleTargetAuras(uint32 newPhase = 0x0); + void RemoveNotOwnSingleTargetAuras(uint32 newPhase = 0x0, bool phaseid = false); void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except = 0); void RemoveAurasWithAttribute(uint32 flags); void RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID); @@ -1837,7 +1847,8 @@ class Unit : public WorldObject uint32 GetCreateHealth() const { return GetUInt32Value(UNIT_FIELD_BASE_HEALTH); } void SetCreateMana(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_MANA, val); } uint32 GetCreateMana() const { return GetUInt32Value(UNIT_FIELD_BASE_MANA); } - uint32 GetCreatePowers(Powers power) const; + uint32 GetPowerIndex(uint32 powerType) const; + int32 GetCreatePowers(Powers power) const; float GetPosStat(Stats stat) const { return GetFloatValue(UNIT_FIELD_POSSTAT0+stat); } float GetNegStat(Stats stat) const { return GetFloatValue(UNIT_FIELD_NEGSTAT0+stat); } float GetCreateStat(Stats stat) const { return m_createStats[stat]; } @@ -1917,7 +1928,7 @@ class Unit : public WorldObject void SetVisible(bool x); // common function for visibility checks for player/creatures with detection code - void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask + void SetInPhase(uint32 id, bool update, bool apply); void UpdateObjectVisibility(bool forced = true); SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; @@ -1993,9 +2004,6 @@ class Unit : public WorldObject uint32 SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim); uint32 SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim); - void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; } - bool IsUnderLastManaUseEffect() const; - void SetContestedPvP(Player* attackedPlayer = NULL); uint32 GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectType damagetype, uint32 CastingTime) const; @@ -2038,17 +2046,18 @@ class Unit : public WorldObject bool IsStopped() const { return !(HasUnitState(UNIT_STATE_MOVING)); } void StopMoving(); - void AddUnitMovementFlag(uint32 f) { m_movementInfo.flags |= f; } - void RemoveUnitMovementFlag(uint32 f) { m_movementInfo.flags &= ~f; } - bool HasUnitMovementFlag(uint32 f) const { return (m_movementInfo.flags & f) == f; } - uint32 GetUnitMovementFlags() const { return m_movementInfo.flags; } - void SetUnitMovementFlags(uint32 f) { m_movementInfo.flags = f; } + void AddUnitMovementFlag(uint32 f) { m_movementInfo.AddMovementFlag(f); } + void RemoveUnitMovementFlag(uint32 f) { m_movementInfo.RemoveMovementFlag(f); } + bool HasUnitMovementFlag(uint32 f) const { return m_movementInfo.HasMovementFlag(f); } + uint32 GetUnitMovementFlags() const { return m_movementInfo.GetMovementFlags(); } + void SetUnitMovementFlags(uint32 f) { m_movementInfo.SetMovementFlags(f); } - void AddExtraUnitMovementFlag(uint16 f) { m_movementInfo.flags2 |= f; } - void RemoveExtraUnitMovementFlag(uint16 f) { m_movementInfo.flags2 &= ~f; } - uint16 HasExtraUnitMovementFlag(uint16 f) const { return m_movementInfo.flags2 & f; } - uint16 GetExtraUnitMovementFlags() const { return m_movementInfo.flags2; } - void SetExtraUnitMovementFlags(uint16 f) { m_movementInfo.flags2 = f; } + void AddExtraUnitMovementFlag(uint16 f) { m_movementInfo.AddExtraMovementFlag(f); } + void RemoveExtraUnitMovementFlag(uint16 f) { m_movementInfo.RemoveExtraMovementFlag(f); } + uint16 HasExtraUnitMovementFlag(uint16 f) const { return m_movementInfo.HasExtraMovementFlag(f); } + uint16 GetExtraUnitMovementFlags() const { return m_movementInfo.GetExtraMovementFlags(); } + void SetExtraUnitMovementFlags(uint16 f) { m_movementInfo.SetExtraMovementFlags(f); } + bool IsSplineEnabled() const; float GetPositionZMinusOffset() const; @@ -2120,7 +2129,7 @@ class Unit : public WorldObject void _ExitVehicle(Position const* exitPosition = NULL); void _EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* aurApp = NULL); - void BuildMovementPacket(ByteBuffer *data) const; + void WriteMovementInfo(WorldPacket& data, Movement::ExtraMovementStatusElement* extras = NULL); bool isMoving() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_MASK_MOVING); } bool isTurning() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_MASK_TURNING); } @@ -2128,7 +2137,7 @@ class Unit : public WorldObject bool IsFlying() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_DISABLE_GRAVITY); } bool IsFalling() const; - void RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker); + void RewardRage(uint32 baseRage, bool attacker); virtual float GetFollowAngle() const { return static_cast<float>(M_PI/2); } @@ -2236,6 +2245,7 @@ class Unit : public WorldObject void DisableSpline(); private: bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const* & spellProcEvent); + bool HandleAuraProcOnPowerAmount(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool * handled); bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); @@ -2250,16 +2260,18 @@ class Unit : public WorldObject float GetCombatRatingReduction(CombatRating cr) const; uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const; + protected: void SetFeared(bool apply); void SetConfused(bool apply); void SetStunned(bool apply); - void SetRooted(bool apply); + void SetRooted(bool apply, bool packetOnly = false); - uint32 m_rootTimes; + uint32 m_movementCounter; ///< Incrementing counter used in movement packets + + private: uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; - uint32 m_lastManaUse; // msecs TimeTrackerSmall m_movesplineTimer; Diminishing m_Diminishing; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 915e6016e22..1e7779065d2 100755..100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -493,10 +493,7 @@ Vehicle* Vehicle::RemovePassenger(Unit* unit) if (_me->IsInWorld()) { if (!_me->GetTransport()) - { - unit->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - unit->m_movementInfo.transport.Reset(); - } + unit->m_movementInfo.ResetTransport(); else unit->m_movementInfo.transport = _me->m_movementInfo.transport; } @@ -538,6 +535,7 @@ void Vehicle::RelocatePassengers() float px, py, pz, po; passenger->m_movementInfo.transport.pos.GetPosition(px, py, pz, po); CalculatePassengerPosition(px, py, pz, &po); + passenger->UpdatePosition(px, py, pz, po); } } @@ -798,7 +796,6 @@ bool VehicleJoinEvent::Execute(uint64, uint32) if (Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE) Passenger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Passenger->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); Passenger->m_movementInfo.transport.pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ); Passenger->m_movementInfo.transport.time = 0; Passenger->m_movementInfo.transport.seat = Seat->first; diff --git a/src/server/game/Entities/Vehicle/VehicleDefines.h b/src/server/game/Entities/Vehicle/VehicleDefines.h index fdc5c94282b..2a800008e8b 100644 --- a/src/server/game/Entities/Vehicle/VehicleDefines.h +++ b/src/server/game/Entities/Vehicle/VehicleDefines.h @@ -32,7 +32,29 @@ enum PowerType POWER_HEAT = 101, POWER_OOZE = 121, POWER_BLOOD = 141, - POWER_WRATH = 142 + POWER_WRATH = 142, + POWER_ARCANE_ENERGY = 143, + POWER_LIFE_ENERGY = 144, + POWER_SUN_ENERGY = 145, + POWER_SWING_VELOCITY = 146, + POWER_SHADOWFLAME_ENERGY = 147, + POWER_BLUE_POWER = 148, + POWER_PURPLE_POWER = 149, + POWER_GREEN_POWER = 150, + POWER_ORANGE_POWER = 151, + POWER_ENERGY_2 = 153, + POWER_ARCANEENERGY = 161, + POWER_WIND_POWER_1 = 162, + POWER_WIND_POWER_2 = 163, + POWER_WIND_POWER_3 = 164, + POWER_FUEL = 165, + POWER_SUN_POWER = 166, + POWER_TWILIGHT_ENERGY = 169, + POWER_VENOM = 174, + POWER_ORANGE_POWER_2 = 176, + POWER_CONSUMING_FLAME = 177, + POWER_PYROCLASTIC_FRENZY = 178, + POWER_FLASHFIRE = 179, }; enum VehicleFlags diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 9e1514f11bd..217919ff574 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -777,8 +777,8 @@ void GameEventMgr::LoadFromDB() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 - QueryResult result = WorldDatabase.Query("SELECT eventEntry, guid, item, maxcount, incrtime, ExtendedCost FROM game_event_npc_vendor ORDER BY guid, slot ASC"); + // 0 1 2 3 4 5 6 + QueryResult result = WorldDatabase.Query("SELECT eventEntry, guid, item, maxcount, incrtime, ExtendedCost, type FROM game_event_npc_vendor ORDER BY guid, slot ASC"); if (!result) TC_LOG_INFO("server.loading", ">> Loaded 0 vendor additions in game events. DB table `game_event_npc_vendor` is empty."); @@ -804,6 +804,7 @@ void GameEventMgr::LoadFromDB() newEntry.maxcount = fields[3].GetUInt32(); newEntry.incrtime = fields[4].GetUInt32(); newEntry.ExtendedCost = fields[5].GetUInt32(); + newEntry.Type = fields[6].GetUInt8(); // get the event npc flag for checking if the npc will be vendor during the event or not uint32 event_npc_flag = 0; NPCFlagList& flist = mGameEventNPCFlags[event_id]; @@ -822,7 +823,7 @@ void GameEventMgr::LoadFromDB() newEntry.entry = data->id; // check validity with event's npcflag - if (!sObjectMgr->IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, NULL, NULL, event_npc_flag)) + if (!sObjectMgr->IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, newEntry.Type, NULL, NULL, event_npc_flag)) continue; vendors.push_back(newEntry); @@ -1151,9 +1152,9 @@ void GameEventMgr::UpdateEventNPCVendor(uint16 event_id, bool activate) for (NPCVendorList::iterator itr = mGameEventVendors[event_id].begin(); itr != mGameEventVendors[event_id].end(); ++itr) { if (activate) - sObjectMgr->AddVendorItem(itr->entry, itr->item, itr->maxcount, itr->incrtime, itr->ExtendedCost, false); + sObjectMgr->AddVendorItem(itr->entry, itr->item, itr->maxcount, itr->incrtime, itr->ExtendedCost, itr->Type, false); else - sObjectMgr->RemoveVendorItem(itr->entry, itr->item, false); + sObjectMgr->RemoveVendorItem(itr->entry, itr->item, itr->Type, false); } } diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index e5c00da5e91..5afa26ec746 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -86,6 +86,7 @@ struct NPCVendorEntry int32 maxcount; // 0 for infinite uint32 incrtime; // time for restore items amount if maxcount != 0 uint32 ExtendedCost; + uint8 Type; // 1 item, 2 currency }; class Player; diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index 931ec0e607d..a464d0c57eb 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -93,6 +93,7 @@ WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, uint64 guid) case HIGHGUID_UNIT: return GetCreature(p, guid); case HIGHGUID_PET: return GetPet(p, guid); case HIGHGUID_DYNAMICOBJECT: return GetDynamicObject(p, guid); + case HIGHGUID_AREATRIGGER: return GetAreaTrigger(p, guid); case HIGHGUID_CORPSE: return GetCorpse(p, guid); default: return NULL; } @@ -129,6 +130,9 @@ Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const& p, uint64 guid, u if (typemask & TYPEMASK_DYNAMICOBJECT) return GetDynamicObject(p, guid); break; + case HIGHGUID_AREATRIGGER: + if (typemask & TYPEMASK_AREATRIGGER) + return GetAreaTrigger(p, guid); case HIGHGUID_CORPSE: break; } @@ -160,6 +164,11 @@ DynamicObject* ObjectAccessor::GetDynamicObject(WorldObject const& u, uint64 gui return GetObjectInMap(guid, u.GetMap(), (DynamicObject*)NULL); } +AreaTrigger* ObjectAccessor::GetAreaTrigger(WorldObject const& u, uint64 guid) +{ + return GetObjectInMap(guid, u.GetMap(), (AreaTrigger*)NULL); +} + Unit* ObjectAccessor::GetUnit(WorldObject const& u, uint64 guid) { return GetObjectInMap(guid, u.GetMap(), (Unit*)NULL); @@ -369,7 +378,6 @@ Corpse* ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia // bones->m_time = m_time; // don't overwrite time // bones->m_type = m_type; // don't overwrite type bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation()); - bones->SetPhaseMask(corpse->GetPhaseMask(), false); bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES); bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0); diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index 849ae25a335..f466d8bd328 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -155,6 +155,7 @@ class ObjectAccessor static GameObject* GetGameObject(WorldObject const& u, uint64 guid); static Transport* GetTransport(WorldObject const& u, uint64 guid); static DynamicObject* GetDynamicObject(WorldObject const& u, uint64 guid); + static AreaTrigger* GetAreaTrigger(WorldObject const& u, uint64 guid); static Unit* GetUnit(WorldObject const&, uint64 guid); static Creature* GetCreature(WorldObject const& u, uint64 guid); static Pet* GetPet(WorldObject const&, uint64 guid); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index b7f2cd3dae4..93c06146c06 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -24,6 +24,8 @@ #include "Chat.h" #include "Common.h" #include "DatabaseEnv.h" +#include "DB2Structure.h" +#include "DB2Stores.h" #include "DisableMgr.h" #include "GameEventMgr.h" #include "GossipDef.h" @@ -172,7 +174,9 @@ LanguageDesc lang_description[LANGUAGES_COUNT] = { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI }, { LANG_ZOMBIE, 0, 0 }, { LANG_GNOMISH_BINARY, 0, 0 }, - { LANG_GOBLIN_BINARY, 0, 0 } + { LANG_GOBLIN_BINARY, 0, 0 }, + { LANG_WORGEN, 69270, SKILL_LANG_WORGEN }, + { LANG_GOBLIN, 69269, SKILL_LANG_GOBLIN } }; LanguageDesc const* GetLanguageDescByID(uint32 lang) @@ -227,6 +231,7 @@ ObjectMgr::ObjectMgr(): _itemTextId(1), _mailId(1), _hiPetNumber(1), + _voidItemId(1), _hiCharGuid(1), _hiCreatureGuid(1), _hiPetGuid(1), @@ -235,15 +240,13 @@ ObjectMgr::ObjectMgr(): _hiGoGuid(1), _hiDoGuid(1), _hiCorpseGuid(1), + _hiAreaTriggerGuid(1), _hiMoTransGuid(1), DBCLocaleIndex(LOCALE_enUS) { for (uint8 i = 0; i < MAX_CLASSES; ++i) - { - _playerClassInfo[i] = NULL; for (uint8 j = 0; j < MAX_RACES; ++j) _playerInfo[j][i] = NULL; - } } ObjectMgr::~ObjectMgr() @@ -254,14 +257,6 @@ ObjectMgr::~ObjectMgr() for (PetLevelInfoContainer::iterator i = _petInfoStore.begin(); i != _petInfoStore.end(); ++i) delete[] i->second; - // free only if loaded - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - { - if (_playerClassInfo[class_]) - delete[] _playerClassInfo[class_]->levelInfo; - delete _playerClassInfo[class_]; - } - for (int race = 0; race < MAX_RACES; ++race) { for (int class_ = 0; class_ < MAX_CLASSES; ++class_) @@ -276,6 +271,7 @@ ObjectMgr::~ObjectMgr() itr->second.Clear(); _cacheTrainerSpellStore.clear(); + _graveyardOrientations.clear(); for (DungeonEncounterContainer::iterator itr =_dungeonEncounterStore.begin(); itr != _dungeonEncounterStore.end(); ++itr) for (DungeonEncounterList::iterator encounterItr = itr->second.begin(); encounterItr != itr->second.end(); ++encounterItr) @@ -296,13 +292,50 @@ void ObjectMgr::AddLocaleString(std::string const& s, LocaleConstant locale, Str } } +void ObjectMgr::LoadGraveyardOrientations() +{ + uint32 oldMSTime = getMSTime(); + + _graveyardOrientations.clear(); + + QueryResult result = WorldDatabase.Query("SELECT id, orientation FROM graveyard_orientation"); + + if (!result) + return; + + do + { + Field* fields = result->Fetch(); + + uint32 id = fields[0].GetUInt32(); + if (!sWorldSafeLocsStore.LookupEntry(id)) + { + TC_LOG_ERROR("server.loading", "Graveyard %u referenced in graveyard_orientation doesn't exist.", id); + continue; + } + _graveyardOrientations[id] = fields[1].GetFloat(); + + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %lu graveyard orientations in %u ms", (unsigned long)_graveyardOrientations.size(), GetMSTimeDiffToNow(oldMSTime)); +} + void ObjectMgr::LoadCreatureLocales() { uint32 oldMSTime = getMSTime(); - _creatureLocaleStore.clear(); // need for reload case + _creatureLocaleStore.clear(); // need for reload case - QueryResult result = WorldDatabase.Query("SELECT entry, name_loc1, subname_loc1, name_loc2, subname_loc2, name_loc3, subname_loc3, name_loc4, subname_loc4, name_loc5, subname_loc5, name_loc6, subname_loc6, name_loc7, subname_loc7, name_loc8, subname_loc8 FROM locales_creature"); + QueryResult result = WorldDatabase.Query("SELECT entry, " + "name_loc1, femaleName_loc1, subname_loc1, " + "name_loc2, femaleName_loc2, subname_loc2, " + "name_loc3, femaleName_loc3, subname_loc3, " + "name_loc4, femaleName_loc4, subname_loc4, " + "name_loc5, femaleName_loc5, subname_loc5, " + "name_loc6, femaleName_loc6, subname_loc6, " + "name_loc7, femaleName_loc7, subname_loc7, " + "name_loc8, femaleName_loc8, subname_loc8 " + "FROM locales_creature"); if (!result) return; @@ -318,8 +351,9 @@ void ObjectMgr::LoadCreatureLocales() for (uint8 i = 1; i < TOTAL_LOCALES; ++i) { LocaleConstant locale = (LocaleConstant) i; - AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.Name); - AddLocaleString(fields[1 + 2 * (i - 1) + 1].GetString(), locale, data.SubName); + AddLocaleString(fields[1 + 3 * (i - 1)].GetString(), locale, data.Name); + AddLocaleString(fields[1 + 3 * (i - 1) + 1].GetString(), locale, data.FemaleName); + AddLocaleString(fields[1 + 3 * (i - 1) + 2].GetString(), locale, data.SubName); } } while (result->NextRow()); @@ -395,19 +429,19 @@ void ObjectMgr::LoadCreatureTemplates() // 0 1 2 3 4 5 6 7 8 QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, " - // 9 10 11 12 13 14 15 16 17 18 19 20 21 - "modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, " - // 22 23 24 25 26 27 28 29 30 31 32 33 + // 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + "modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, " + // 23 24 25 26 27 28 29 30 31 32 33 34 "scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, " - // 34 35 36 37 38 39 40 41 42 43 - "dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, " - // 44 45 46 47 48 49 50 51 52 53 54 - "type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, " - // 55 56 57 58 59 60 61 62 63 64 65 66 67 - "spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, " - // 68 69 70 71 72 73 74 75 76 77 78 - "InhabitType, HoverHeight, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, " - // 79 80 81 82 83 84 + // 35 36 37 38 39 40 41 42 43 + "dynamicflags, family, trainer_type, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, " + // 44 45 46 47 48 49 50 51 52 53 54 + "type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, " + // 55 56 57 58 59 60 61 62 63 64 65 66 67 68 + "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, " + // 69 70 71 72 73 74 75 76 77 78 79 80 + "InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, " + // 81 82 83 84 85 86 " questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName " "FROM creature_template;"); @@ -441,70 +475,73 @@ void ObjectMgr::LoadCreatureTemplates() creatureTemplate.Modelid3 = fields[8].GetUInt32(); creatureTemplate.Modelid4 = fields[9].GetUInt32(); creatureTemplate.Name = fields[10].GetString(); - creatureTemplate.SubName = fields[11].GetString(); - creatureTemplate.IconName = fields[12].GetString(); - creatureTemplate.GossipMenuId = fields[13].GetUInt32(); - creatureTemplate.minlevel = fields[14].GetUInt8(); - creatureTemplate.maxlevel = fields[15].GetUInt8(); - creatureTemplate.expansion = uint32(fields[16].GetInt16()); - creatureTemplate.faction = uint32(fields[17].GetUInt16()); - creatureTemplate.npcflag = fields[18].GetUInt32(); - creatureTemplate.speed_walk = fields[19].GetFloat(); - creatureTemplate.speed_run = fields[20].GetFloat(); - creatureTemplate.scale = fields[21].GetFloat(); - creatureTemplate.rank = uint32(fields[22].GetUInt8()); - creatureTemplate.mindmg = fields[23].GetFloat(); - creatureTemplate.maxdmg = fields[24].GetFloat(); - creatureTemplate.dmgschool = uint32(fields[25].GetInt8()); - creatureTemplate.attackpower = fields[26].GetUInt32(); - creatureTemplate.dmg_multiplier = fields[27].GetFloat(); - creatureTemplate.baseattacktime = fields[28].GetUInt32(); - creatureTemplate.rangeattacktime = fields[29].GetUInt32(); - creatureTemplate.unit_class = uint32(fields[30].GetUInt8()); - creatureTemplate.unit_flags = fields[31].GetUInt32(); - creatureTemplate.unit_flags2 = fields[32].GetUInt32(); - creatureTemplate.dynamicflags = fields[33].GetUInt32(); - creatureTemplate.family = uint32(fields[34].GetUInt8()); - creatureTemplate.trainer_type = uint32(fields[35].GetUInt8()); - creatureTemplate.trainer_spell = fields[36].GetUInt32(); - creatureTemplate.trainer_class = uint32(fields[37].GetUInt8()); - creatureTemplate.trainer_race = uint32(fields[38].GetUInt8()); - creatureTemplate.minrangedmg = fields[39].GetFloat(); - creatureTemplate.maxrangedmg = fields[40].GetFloat(); - creatureTemplate.rangedattackpower = uint32(fields[41].GetUInt16()); - creatureTemplate.type = uint32(fields[42].GetUInt8()); - creatureTemplate.type_flags = fields[43].GetUInt32(); - creatureTemplate.lootid = fields[44].GetUInt32(); - creatureTemplate.pickpocketLootId = fields[45].GetUInt32(); - creatureTemplate.SkinLootId = fields[46].GetUInt32(); + creatureTemplate.FemaleName = fields[11].GetString(); + creatureTemplate.SubName = fields[12].GetString(); + creatureTemplate.IconName = fields[13].GetString(); + creatureTemplate.GossipMenuId = fields[14].GetUInt32(); + creatureTemplate.minlevel = fields[15].GetUInt8(); + creatureTemplate.maxlevel = fields[16].GetUInt8(); + creatureTemplate.expansion = uint32(fields[17].GetInt16()); + creatureTemplate.expansionUnknown = uint32(fields[18].GetUInt16()); + creatureTemplate.faction = uint32(fields[19].GetUInt16()); + creatureTemplate.npcflag = fields[20].GetUInt32(); + creatureTemplate.speed_walk = fields[21].GetFloat(); + creatureTemplate.speed_run = fields[22].GetFloat(); + creatureTemplate.scale = fields[23].GetFloat(); + creatureTemplate.rank = uint32(fields[24].GetUInt8()); + creatureTemplate.mindmg = fields[25].GetFloat(); + creatureTemplate.maxdmg = fields[26].GetFloat(); + creatureTemplate.dmgschool = uint32(fields[27].GetInt8()); + creatureTemplate.attackpower = fields[28].GetUInt32(); + creatureTemplate.dmg_multiplier = fields[29].GetFloat(); + creatureTemplate.baseattacktime = fields[30].GetUInt32(); + creatureTemplate.rangeattacktime = fields[31].GetUInt32(); + creatureTemplate.unit_class = uint32(fields[32].GetUInt8()); + creatureTemplate.unit_flags = fields[33].GetUInt32(); + creatureTemplate.unit_flags2 = fields[34].GetUInt32(); + creatureTemplate.dynamicflags = fields[35].GetUInt32(); + creatureTemplate.family = uint32(fields[36].GetUInt8()); + creatureTemplate.trainer_type = uint32(fields[37].GetUInt8()); + creatureTemplate.trainer_class = uint32(fields[38].GetUInt8()); + creatureTemplate.trainer_race = uint32(fields[39].GetUInt8()); + creatureTemplate.minrangedmg = fields[40].GetFloat(); + creatureTemplate.maxrangedmg = fields[41].GetFloat(); + creatureTemplate.rangedattackpower = uint32(fields[42].GetUInt16()); + creatureTemplate.type = uint32(fields[43].GetUInt8()); + creatureTemplate.type_flags = fields[44].GetUInt32(); + creatureTemplate.type_flags2 = fields[45].GetUInt32(); + creatureTemplate.lootid = fields[46].GetUInt32(); + creatureTemplate.pickpocketLootId = fields[47].GetUInt32(); + creatureTemplate.SkinLootId = fields[48].GetUInt32(); for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - creatureTemplate.resistance[i] = fields[47 + i -1].GetInt16(); + creatureTemplate.resistance[i] = fields[49 + i - 1].GetInt16(); for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) - creatureTemplate.spells[i] = fields[53 + i].GetUInt32(); - - creatureTemplate.PetSpellDataId = fields[61].GetUInt32(); - creatureTemplate.VehicleId = fields[62].GetUInt32(); - creatureTemplate.mingold = fields[63].GetUInt32(); - creatureTemplate.maxgold = fields[64].GetUInt32(); - creatureTemplate.AIName = fields[65].GetString(); - creatureTemplate.MovementType = uint32(fields[66].GetUInt8()); - creatureTemplate.InhabitType = uint32(fields[67].GetUInt8()); - creatureTemplate.HoverHeight = fields[68].GetFloat(); - creatureTemplate.ModHealth = fields[69].GetFloat(); - creatureTemplate.ModMana = fields[70].GetFloat(); - creatureTemplate.ModArmor = fields[71].GetFloat(); - creatureTemplate.RacialLeader = fields[72].GetBool(); + creatureTemplate.spells[i] = fields[55 + i].GetUInt32(); + + creatureTemplate.PetSpellDataId = fields[63].GetUInt32(); + creatureTemplate.VehicleId = fields[64].GetUInt32(); + creatureTemplate.mingold = fields[65].GetUInt32(); + creatureTemplate.maxgold = fields[66].GetUInt32(); + creatureTemplate.AIName = fields[67].GetString(); + creatureTemplate.MovementType = uint32(fields[68].GetUInt8()); + creatureTemplate.InhabitType = uint32(fields[69].GetUInt8()); + creatureTemplate.HoverHeight = fields[70].GetFloat(); + creatureTemplate.ModHealth = fields[71].GetFloat(); + creatureTemplate.ModMana = fields[72].GetFloat(); + creatureTemplate.ModManaExtra = fields[73].GetFloat(); + creatureTemplate.ModArmor = fields[74].GetFloat(); + creatureTemplate.RacialLeader = fields[75].GetBool(); for (uint8 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) - creatureTemplate.questItems[i] = fields[73 + i].GetUInt32(); + creatureTemplate.questItems[i] = fields[76 + i].GetUInt32(); - creatureTemplate.movementId = fields[79].GetUInt32(); - creatureTemplate.RegenHealth = fields[80].GetBool(); - creatureTemplate.MechanicImmuneMask = fields[81].GetUInt32(); - creatureTemplate.flags_extra = fields[82].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[83].GetCString()); + creatureTemplate.movementId = fields[82].GetUInt32(); + creatureTemplate.RegenHealth = fields[83].GetBool(); + creatureTemplate.MechanicImmuneMask = fields[84].GetUInt32(); + creatureTemplate.flags_extra = fields[85].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[86].GetCString()); ++count; } @@ -719,12 +756,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) continue; } - if (cInfo->trainer_spell != difficultyInfo->trainer_spell) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); - continue; - } - if (cInfo->type != difficultyInfo->type) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, type %u) has different `type` in difficulty %u mode (Entry: %u, type %u).", @@ -945,10 +976,16 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) if (cInfo->expansion > (MAX_EXPANSIONS - 1)) { - TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with expansion %u. Ignored and set to 0.", cInfo->Entry, cInfo->expansion); + TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with `exp` %u. Ignored and set to 0.", cInfo->Entry, cInfo->expansion); const_cast<CreatureTemplate*>(cInfo)->expansion = 0; } + if (cInfo->expansionUnknown > MAX_EXPANSIONS) + { + TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with `exp_unk` %u. Ignored and set to 0.", cInfo->Entry, cInfo->expansionUnknown); + const_cast<CreatureTemplate*>(cInfo)->expansionUnknown = 0; + } + if (uint32 badFlags = (cInfo->flags_extra & ~CREATURE_FLAG_EXTRA_DB_ALLOWED)) { TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with disallowed `flags_extra` %u, removing incorrect flag.", cInfo->Entry, badFlags); @@ -1601,8 +1638,8 @@ void ObjectMgr::LoadCreatures() // 0 1 2 3 4 5 6 7 8 9 10 QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, " - // 11 12 13 14 15 16 17 18 19 20 21 - "currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags " + // 11 12 13 14 15 16 17 18 19 20 21 22 23 + "currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags, creature.phaseid, creature.phasegroup " "FROM creature " "LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid " "LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid"); @@ -1659,17 +1696,19 @@ void ObjectMgr::LoadCreatures() data.npcflag = fields[19].GetUInt32(); data.unit_flags = fields[20].GetUInt32(); data.dynamicflags = fields[21].GetUInt32(); + data.phaseid = fields[22].GetUInt32(); + data.phaseGroup = fields[23].GetUInt32(); MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); if (!mapEntry) { - TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u) that spawned at not existed map (Id: %u), skipped.", guid, data.mapid); + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) that spawned at not existed map (Id: %u), skipped.", guid, data.id, data.mapid); continue; } // Skip spawnMask check for transport maps if (!IsTransportMap(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid]) - TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u).", guid, data.spawnMask, data.mapid); + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u) spawnMasks[data.mapid]: %u.", guid, data.id, data.spawnMask, data.mapid, spawnMasks[data.mapid]); bool ok = true; for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff) @@ -1728,6 +1767,12 @@ void ObjectMgr::LoadCreatures() data.phaseMask = 1; } + if (data.phaseGroup && data.phaseid) + { + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.id); + data.phaseGroup = 0; + } + // Add to grid if not managed by the game event or pool system if (gameEvent == 0 && PoolId == 0) AddCreatureToGrid(guid, &data); @@ -1911,8 +1956,8 @@ void ObjectMgr::LoadGameobjects() // 0 1 2 3 4 5 6 QueryResult result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation, " - // 7 8 9 10 11 12 13 14 15 16 17 - "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, eventEntry, pool_entry " + // 7 8 9 10 11 12 13 14 15 16 17 18 19 + "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, eventEntry, pool_entry, phaseid, phasegroup " "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid " "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid"); @@ -2008,7 +2053,15 @@ void ObjectMgr::LoadGameobjects() data.phaseMask = fields[15].GetUInt32(); int16 gameEvent = fields[16].GetInt8(); - uint32 PoolId = fields[17].GetUInt32(); + uint32 PoolId = fields[17].GetUInt32(); + data.phaseid = fields[18].GetUInt32(); + data.phaseGroup = fields[19].GetUInt32(); + + if (data.phaseGroup && data.phaseid) + { + TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: %u Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.id); + data.phaseGroup = 0; + } if (data.rotation2 < -1.0f || data.rotation2 > 1.0f) { @@ -2210,582 +2263,504 @@ void ObjectMgr::LoadItemLocales() TC_LOG_INFO("server.loading", ">> Loaded %lu Item locale strings in %u ms", (unsigned long)_itemLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadItemTemplates() +void FillItemDamageFields(float* minDamage, float* maxDamage, float* dps, uint32 itemLevel, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32 delay, float statScalingFactor, uint32 inventoryType, uint32 flags2) { - uint32 oldMSTime = getMSTime(); - - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - QueryResult result = WorldDatabase.Query("SELECT entry, class, subclass, SoundOverrideSubclass, name, displayid, Quality, Flags, FlagsExtra, BuyCount, BuyPrice, SellPrice, InventoryType, " - // 13 14 15 16 17 18 19 20 - "AllowableClass, AllowableRace, ItemLevel, RequiredLevel, RequiredSkill, RequiredSkillRank, requiredspell, requiredhonorrank, " - // 21 22 23 24 25 26 27 28 - "RequiredCityRank, RequiredReputationFaction, RequiredReputationRank, maxcount, stackable, ContainerSlots, StatsCount, stat_type1, " - // 29 30 31 32 33 34 35 36 37 38 - "stat_value1, stat_type2, stat_value2, stat_type3, stat_value3, stat_type4, stat_value4, stat_type5, stat_value5, stat_type6, " - // 39 40 41 42 43 44 45 46 47 - "stat_value6, stat_type7, stat_value7, stat_type8, stat_value8, stat_type9, stat_value9, stat_type10, stat_value10, " - // 48 49 50 51 52 53 54 55 56 57 58 - "ScalingStatDistribution, ScalingStatValue, dmg_min1, dmg_max1, dmg_type1, dmg_min2, dmg_max2, dmg_type2, armor, holy_res, fire_res, " - // 59 60 61 62 63 64 65 66 67 68 - "nature_res, frost_res, shadow_res, arcane_res, delay, ammo_type, RangedModRange, spellid_1, spelltrigger_1, spellcharges_1, " - // 69 70 71 72 73 74 75 - "spellppmRate_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1, spellid_2, spelltrigger_2, spellcharges_2, " - // 76 77 78 79 80 81 82 - "spellppmRate_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2, spellid_3, spelltrigger_3, spellcharges_3, " - // 83 84 85 86 87 88 89 - "spellppmRate_3, spellcooldown_3, spellcategory_3, spellcategorycooldown_3, spellid_4, spelltrigger_4, spellcharges_4, " - // 90 91 92 93 94 95 96 - "spellppmRate_4, spellcooldown_4, spellcategory_4, spellcategorycooldown_4, spellid_5, spelltrigger_5, spellcharges_5, " - // 97 98 99 100 101 102 103 104 105 - "spellppmRate_5, spellcooldown_5, spellcategory_5, spellcategorycooldown_5, bonding, description, PageText, LanguageID, PageMaterial, " - // 106 107 108 109 110 111 112 113 114 115 116 117 - "startquest, lockid, Material, sheath, RandomProperty, RandomSuffix, block, itemset, MaxDurability, area, Map, BagFamily, " - // 118 119 120 121 122 123 124 125 - "TotemCategory, socketColor_1, socketContent_1, socketColor_2, socketContent_2, socketColor_3, socketContent_3, socketBonus, " - // 126 127 128 129 130 131 132 133 - "GemProperties, RequiredDisenchantSkill, ArmorDamageModifier, duration, ItemLimitCategory, HolidayId, ScriptName, DisenchantID, " - // 134 135 136 - "FoodType, minMoneyLoot, maxMoneyLoot, flagsCustom FROM item_template"); - - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 item templates. DB table `item_template` is empty."); + *minDamage = *maxDamage = *dps = 0.0f; + if (itemClass != ITEM_CLASS_WEAPON || quality > ITEM_QUALITY_ARTIFACT) return; - } - _itemTemplateStore.rehash(result->GetRowCount()); - uint32 count = 0; - bool enforceDBCAttributes = sWorld->getBoolConfig(CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES); + DBCStorage<ItemDamageEntry>* store = NULL; + // get the right store here + if (inventoryType > 0xD + 13) + return; - do + switch (inventoryType) { - Field* fields = result->Fetch(); - - uint32 entry = fields[0].GetUInt32(); - - ItemTemplate& itemTemplate = _itemTemplateStore[entry]; - - itemTemplate.ItemId = entry; - itemTemplate.Class = uint32(fields[1].GetUInt8()); - itemTemplate.SubClass = uint32(fields[2].GetUInt8()); - itemTemplate.SoundOverrideSubclass = int32(fields[3].GetInt8()); - itemTemplate.Name1 = fields[4].GetString(); - itemTemplate.DisplayInfoID = fields[5].GetUInt32(); - itemTemplate.Quality = uint32(fields[6].GetUInt8()); - itemTemplate.Flags = fields[7].GetUInt32(); - itemTemplate.Flags2 = fields[8].GetUInt32(); - itemTemplate.BuyCount = uint32(fields[9].GetUInt8()); - itemTemplate.BuyPrice = int32(fields[10].GetInt64()); - itemTemplate.SellPrice = fields[11].GetUInt32(); - itemTemplate.InventoryType = uint32(fields[12].GetUInt8()); - itemTemplate.AllowableClass = fields[13].GetInt32(); - itemTemplate.AllowableRace = fields[14].GetInt32(); - itemTemplate.ItemLevel = uint32(fields[15].GetUInt16()); - itemTemplate.RequiredLevel = uint32(fields[16].GetUInt8()); - itemTemplate.RequiredSkill = uint32(fields[17].GetUInt16()); - itemTemplate.RequiredSkillRank = uint32(fields[18].GetUInt16()); - itemTemplate.RequiredSpell = fields[19].GetUInt32(); - itemTemplate.RequiredHonorRank = fields[20].GetUInt32(); - itemTemplate.RequiredCityRank = fields[21].GetUInt32(); - itemTemplate.RequiredReputationFaction = uint32(fields[22].GetUInt16()); - itemTemplate.RequiredReputationRank = uint32(fields[23].GetUInt16()); - itemTemplate.MaxCount = fields[24].GetInt32(); - itemTemplate.Stackable = fields[25].GetInt32(); - itemTemplate.ContainerSlots = uint32(fields[26].GetUInt8()); - itemTemplate.StatsCount = uint32(fields[27].GetUInt8()); - - for (uint8 i = 0; i < itemTemplate.StatsCount; ++i) - { - itemTemplate.ItemStat[i].ItemStatType = uint32(fields[28 + i*2].GetUInt8()); - itemTemplate.ItemStat[i].ItemStatValue = int32(fields[29 + i*2].GetInt16()); - } - - itemTemplate.ScalingStatDistribution = uint32(fields[48].GetUInt16()); - itemTemplate.ScalingStatValue = fields[49].GetInt32(); - - for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) - { - itemTemplate.Damage[i].DamageMin = fields[50 + i*3].GetFloat(); - itemTemplate.Damage[i].DamageMax = fields[51 + i*3].GetFloat(); - itemTemplate.Damage[i].DamageType = uint32(fields[52 + i*3].GetUInt8()); - } - - itemTemplate.Armor = uint32(fields[56].GetUInt16()); - itemTemplate.HolyRes = uint32(fields[57].GetUInt8()); - itemTemplate.FireRes = uint32(fields[58].GetUInt8()); - itemTemplate.NatureRes = uint32(fields[59].GetUInt8()); - itemTemplate.FrostRes = uint32(fields[60].GetUInt8()); - itemTemplate.ShadowRes = uint32(fields[61].GetUInt8()); - itemTemplate.ArcaneRes = uint32(fields[62].GetUInt8()); - itemTemplate.Delay = uint32(fields[63].GetUInt16()); - itemTemplate.AmmoType = uint32(fields[64].GetUInt8()); - itemTemplate.RangedModRange = fields[65].GetFloat(); - - for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) - { - itemTemplate.Spells[i].SpellId = fields[66 + i*7 ].GetInt32(); - itemTemplate.Spells[i].SpellTrigger = uint32(fields[67 + i*7].GetUInt8()); - itemTemplate.Spells[i].SpellCharges = int32(fields[68 + i*7].GetInt16()); - itemTemplate.Spells[i].SpellPPMRate = fields[69 + i*7].GetFloat(); - itemTemplate.Spells[i].SpellCooldown = fields[70 + i*7].GetInt32(); - itemTemplate.Spells[i].SpellCategory = uint32(fields[71 + i*7].GetUInt16()); - itemTemplate.Spells[i].SpellCategoryCooldown = fields[72 + i*7].GetInt32(); - } - - itemTemplate.Bonding = uint32(fields[101].GetUInt8()); - itemTemplate.Description = fields[102].GetString(); - itemTemplate.PageText = fields[103].GetUInt32(); - itemTemplate.LanguageID = uint32(fields[104].GetUInt8()); - itemTemplate.PageMaterial = uint32(fields[105].GetUInt8()); - itemTemplate.StartQuest = fields[106].GetUInt32(); - itemTemplate.LockID = fields[107].GetUInt32(); - itemTemplate.Material = int32(fields[108].GetInt8()); - itemTemplate.Sheath = uint32(fields[109].GetUInt8()); - itemTemplate.RandomProperty = fields[110].GetUInt32(); - itemTemplate.RandomSuffix = fields[111].GetInt32(); - itemTemplate.Block = fields[112].GetUInt32(); - itemTemplate.ItemSet = fields[113].GetUInt32(); - itemTemplate.MaxDurability = uint32(fields[114].GetUInt16()); - itemTemplate.Area = fields[115].GetUInt32(); - itemTemplate.Map = uint32(fields[116].GetUInt16()); - itemTemplate.BagFamily = fields[117].GetUInt32(); - itemTemplate.TotemCategory = fields[118].GetUInt32(); - - for (uint8 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) - { - itemTemplate.Socket[i].Color = uint32(fields[119 + i*2].GetUInt8()); - itemTemplate.Socket[i].Content = fields[120 + i*2].GetUInt32(); - } - - itemTemplate.socketBonus = fields[125].GetUInt32(); - itemTemplate.GemProperties = fields[126].GetUInt32(); - itemTemplate.RequiredDisenchantSkill = uint32(fields[127].GetInt16()); - itemTemplate.ArmorDamageModifier = fields[128].GetFloat(); - itemTemplate.Duration = fields[129].GetUInt32(); - itemTemplate.ItemLimitCategory = uint32(fields[130].GetInt16()); - itemTemplate.HolidayId = fields[131].GetUInt32(); - itemTemplate.ScriptId = sObjectMgr->GetScriptId(fields[132].GetCString()); - itemTemplate.DisenchantID = fields[133].GetUInt32(); - itemTemplate.FoodType = uint32(fields[134].GetUInt8()); - itemTemplate.MinMoneyLoot = fields[135].GetUInt32(); - itemTemplate.MaxMoneyLoot = fields[136].GetUInt32(); - itemTemplate.FlagsCu = fields[137].GetUInt32(); - - // Checks - - ItemEntry const* dbcitem = sItemStore.LookupEntry(entry); - - if (dbcitem) - { - if (itemTemplate.Class != dbcitem->Class) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have a correct class %u, must be %u .", entry, itemTemplate.Class, dbcitem->Class); - if (enforceDBCAttributes) - itemTemplate.Class = dbcitem->Class; - } - - if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclass) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have a correct SoundOverrideSubclass (%i), must be %i .", entry, itemTemplate.SoundOverrideSubclass, dbcitem->SoundOverrideSubclass); - if (enforceDBCAttributes) - itemTemplate.SoundOverrideSubclass = dbcitem->SoundOverrideSubclass; - } - if (itemTemplate.Material != dbcitem->Material) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have a correct material (%i), must be %i .", entry, itemTemplate.Material, dbcitem->Material); - if (enforceDBCAttributes) - itemTemplate.Material = dbcitem->Material; - } - if (itemTemplate.InventoryType != dbcitem->InventoryType) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have a correct inventory type (%u), must be %u .", entry, itemTemplate.InventoryType, dbcitem->InventoryType); - if (enforceDBCAttributes) - itemTemplate.InventoryType = dbcitem->InventoryType; - } - if (itemTemplate.DisplayInfoID != dbcitem->DisplayId) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have a correct display id (%u), must be %u .", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayId); - if (enforceDBCAttributes) - itemTemplate.DisplayInfoID = dbcitem->DisplayId; - } - if (itemTemplate.Sheath != dbcitem->Sheath) + case INVTYPE_AMMO: + store = &sItemDamageAmmoStore; + break; + case INVTYPE_2HWEAPON: + if (flags2 & ITEM_FLAGS_EXTRA_CASTER_WEAPON) + store = &sItemDamageTwoHandCasterStore; + else + store = &sItemDamageTwoHandStore; + break; + case INVTYPE_RANGED: + case INVTYPE_THROWN: + case INVTYPE_RANGEDRIGHT: + switch (itemSubClass) { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have a correct sheathid (%u), must be %u .", entry, itemTemplate.Sheath, dbcitem->Sheath); - if (enforceDBCAttributes) - itemTemplate.Sheath = dbcitem->Sheath; + case ITEM_SUBCLASS_WEAPON_WAND: + store = &sItemDamageWandStore; + break; + case ITEM_SUBCLASS_WEAPON_THROWN: + store = &sItemDamageThrownStore; + break; + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_GUN: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + store = &sItemDamageRangedStore; + break; + default: + return; } + break; + case INVTYPE_WEAPON: + case INVTYPE_WEAPONMAINHAND: + case INVTYPE_WEAPONOFFHAND: + if (flags2 & ITEM_FLAGS_EXTRA_CASTER_WEAPON) + store = &sItemDamageOneHandCasterStore; + else + store = &sItemDamageOneHandStore; + break; + default: + return; + } - } - else - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not exist in item.dbc! (not correct id?).", entry); - - if (itemTemplate.Class >= MAX_ITEM_CLASS) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Class value (%u)", entry, itemTemplate.Class); - itemTemplate.Class = ITEM_CLASS_MISC; - } - - if (itemTemplate.SubClass >= MaxItemSubclassValues[itemTemplate.Class]) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Subclass value (%u) for class %u", entry, itemTemplate.SubClass, itemTemplate.Class); - itemTemplate.SubClass = 0;// exist for all item classes - } - - if (itemTemplate.Quality >= MAX_ITEM_QUALITY) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Quality value (%u)", entry, itemTemplate.Quality); - itemTemplate.Quality = ITEM_QUALITY_NORMAL; - } - - if (itemTemplate.Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) - { - if (FactionEntry const* faction = sFactionStore.LookupEntry(HORDE)) - if ((itemTemplate.AllowableRace & faction->BaseRepRaceMask[0]) == 0) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `AllowableRace` races, not compatible with ITEM_FLAGS_EXTRA_HORDE_ONLY (%u) in Flags field, item cannot be equipped or used by these races.", - entry, itemTemplate.AllowableRace, ITEM_FLAGS_EXTRA_HORDE_ONLY); - - if (itemTemplate.Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `Flags2` flags (ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) and ITEM_FLAGS_EXTRA_HORDE_ONLY (%u) in Flags field, this is a wrong combination.", - entry, ITEM_FLAGS_EXTRA_ALLIANCE_ONLY, ITEM_FLAGS_EXTRA_HORDE_ONLY); - } - else if (itemTemplate.Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) - { - if (FactionEntry const* faction = sFactionStore.LookupEntry(ALLIANCE)) - if ((itemTemplate.AllowableRace & faction->BaseRepRaceMask[0]) == 0) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has value (%u) in `AllowableRace` races, not compatible with ITEM_FLAGS_EXTRA_ALLIANCE_ONLY (%u) in Flags field, item cannot be equipped or used by these races.", - entry, itemTemplate.AllowableRace, ITEM_FLAGS_EXTRA_ALLIANCE_ONLY); - } - - if (itemTemplate.BuyCount <= 0) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong BuyCount value (%u), set to default(1).", entry, itemTemplate.BuyCount); - itemTemplate.BuyCount = 1; - } - - if (itemTemplate.InventoryType >= MAX_INVTYPE) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong InventoryType value (%u)", entry, itemTemplate.InventoryType); - itemTemplate.InventoryType = INVTYPE_NON_EQUIP; - } - - if (itemTemplate.RequiredSkill >= MAX_SKILL_TYPE) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong RequiredSkill value (%u)", entry, itemTemplate.RequiredSkill); - itemTemplate.RequiredSkill = 0; - } - - { - // can be used in equip slot, as page read use in inventory, or spell casting at use - bool req = itemTemplate.InventoryType != INVTYPE_NON_EQUIP || itemTemplate.PageText; - if (!req) - for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j) - { - if (itemTemplate.Spells[j].SpellId) - { - req = true; - break; - } - } - - if (req) - { - if (!(itemTemplate.AllowableClass & CLASSMASK_ALL_PLAYABLE)) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have any playable classes (%u) in `AllowableClass` and can't be equipped or used.", entry, itemTemplate.AllowableClass); + if (!store) + return; - if (!(itemTemplate.AllowableRace & RACEMASK_ALL_PLAYABLE)) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have any playable races (%u) in `AllowableRace` and can't be equipped or used.", entry, itemTemplate.AllowableRace); - } - } + ItemDamageEntry const* damageInfo = store->LookupEntry(itemLevel); + if (!damageInfo) + return; - if (itemTemplate.RequiredSpell && !sSpellMgr->GetSpellInfo(itemTemplate.RequiredSpell)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has a wrong (non-existing) spell in RequiredSpell (%u)", entry, itemTemplate.RequiredSpell); - itemTemplate.RequiredSpell = 0; - } + *dps = damageInfo->DPS[quality]; + float avgDamage = *dps * delay * 0.001f; + *minDamage = (statScalingFactor * -0.5f + 1.0f) * avgDamage; + *maxDamage = floor(float(avgDamage* (statScalingFactor * 0.5f + 1.0f) + 0.5f)); +} - if (itemTemplate.RequiredReputationRank >= MAX_REPUTATION_RANK) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong reputation rank in RequiredReputationRank (%u), item can't be used.", entry, itemTemplate.RequiredReputationRank); +uint32 FillItemArmor(uint32 itemlevel, uint32 itemClass, uint32 itemSubclass, uint32 quality, uint32 inventoryType) +{ + if (quality > ITEM_QUALITY_ARTIFACT) + return 0; - if (itemTemplate.RequiredReputationFaction) - { - if (!sFactionStore.LookupEntry(itemTemplate.RequiredReputationFaction)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong (not existing) faction in RequiredReputationFaction (%u)", entry, itemTemplate.RequiredReputationFaction); - itemTemplate.RequiredReputationFaction = 0; - } + // all items but shields + if (itemClass != ITEM_CLASS_ARMOR || itemSubclass != ITEM_SUBCLASS_ARMOR_SHIELD) + { + ItemArmorQualityEntry const* armorQuality = sItemArmorQualityStore.LookupEntry(itemlevel); + ItemArmorTotalEntry const* armorTotal = sItemArmorTotalStore.LookupEntry(itemlevel); + if (!armorQuality || !armorTotal) + return 0; - if (itemTemplate.RequiredReputationRank == MIN_REPUTATION_RANK) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has min. reputation rank in RequiredReputationRank (0) but RequiredReputationFaction > 0, faction setting is useless.", entry); - } + if (inventoryType == INVTYPE_ROBE) + inventoryType = INVTYPE_CHEST; - if (itemTemplate.MaxCount < -1) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has too large negative in maxcount (%i), replace by value (-1) no storing limits.", entry, itemTemplate.MaxCount); - itemTemplate.MaxCount = -1; - } + ArmorLocationEntry const* location = sArmorLocationStore.LookupEntry(inventoryType); + if (!location) + return 0; - if (itemTemplate.Stackable == 0) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong value in stackable (%i), replace by default 1.", entry, itemTemplate.Stackable); - itemTemplate.Stackable = 1; - } - else if (itemTemplate.Stackable < -1) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has too large negative in stackable (%i), replace by value (-1) no stacking limits.", entry, itemTemplate.Stackable); - itemTemplate.Stackable = -1; - } + if (itemSubclass < ITEM_SUBCLASS_ARMOR_CLOTH || itemSubclass > ITEM_SUBCLASS_ARMOR_PLATE) + return 0; - if (itemTemplate.ContainerSlots > MAX_BAG_SIZE) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has too large value in ContainerSlots (%u), replace by hardcoded limit (%u).", entry, itemTemplate.ContainerSlots, MAX_BAG_SIZE); - itemTemplate.ContainerSlots = MAX_BAG_SIZE; - } + return uint32(armorQuality->Value[quality] * armorTotal->Value[itemSubclass - 1] * location->Value[itemSubclass - 1] + 0.5f); + } - if (itemTemplate.StatsCount > MAX_ITEM_PROTO_STATS) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).", entry, itemTemplate.StatsCount, MAX_ITEM_PROTO_STATS); - itemTemplate.StatsCount = MAX_ITEM_PROTO_STATS; - } + // shields + ItemArmorShieldEntry const* shield = sItemArmorShieldStore.LookupEntry(itemlevel); + if (!shield) + return 0; - for (uint8 j = 0; j < itemTemplate.StatsCount; ++j) - { - // for ItemStatValue != 0 - if (itemTemplate.ItemStat[j].ItemStatValue && itemTemplate.ItemStat[j].ItemStatType >= MAX_ITEM_MOD) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong (non-existing?) stat_type%d (%u)", entry, j+1, itemTemplate.ItemStat[j].ItemStatType); - itemTemplate.ItemStat[j].ItemStatType = 0; - } + return uint32(shield->Value[quality] + 0.5f); +} - switch (itemTemplate.ItemStat[j].ItemStatType) - { - case ITEM_MOD_SPELL_HEALING_DONE: - case ITEM_MOD_SPELL_DAMAGE_DONE: - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has deprecated stat_type%d (%u)", entry, j+1, itemTemplate.ItemStat[j].ItemStatType); - break; - default: - break; - } - } +uint32 FillMaxDurability(uint32 itemClass, uint32 itemSubClass, uint32 inventoryType, uint32 quality, uint32 itemLevel) +{ + if (itemClass != ITEM_CLASS_ARMOR && itemClass != ITEM_CLASS_WEAPON) + return 0; - for (uint8 j = 0; j < MAX_ITEM_PROTO_DAMAGES; ++j) - { - if (itemTemplate.Damage[j].DamageType >= MAX_SPELL_SCHOOL) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong dmg_type%d (%u)", entry, j+1, itemTemplate.Damage[j].DamageType); - itemTemplate.Damage[j].DamageType = 0; - } - } + static float const qualityMultipliers[MAX_ITEM_QUALITY] = + { + 1.0f, 1.0f, 1.0f, 1.17f, 1.37f, 1.68f, 0.0f, 0.0f + }; - // special format - if ((itemTemplate.Spells[0].SpellId == 483) || (itemTemplate.Spells[0].SpellId == 55884)) - { - // spell_1 - if (itemTemplate.Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format", entry, 0+1, itemTemplate.Spells[0].SpellTrigger); - itemTemplate.Spells[0].SpellId = 0; - itemTemplate.Spells[0].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - itemTemplate.Spells[1].SpellId = 0; - itemTemplate.Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } + static float const armorMultipliers[MAX_INVTYPE] = + { + 0.00f, // INVTYPE_NON_EQUIP + 0.59f, // INVTYPE_HEAD + 0.00f, // INVTYPE_NECK + 0.59f, // INVTYPE_SHOULDERS + 0.00f, // INVTYPE_BODY + 1.00f, // INVTYPE_CHEST + 0.35f, // INVTYPE_WAIST + 0.75f, // INVTYPE_LEGS + 0.49f, // INVTYPE_FEET + 0.35f, // INVTYPE_WRISTS + 0.35f, // INVTYPE_HANDS + 0.00f, // INVTYPE_FINGER + 0.00f, // INVTYPE_TRINKET + 0.00f, // INVTYPE_WEAPON + 1.00f, // INVTYPE_SHIELD + 0.00f, // INVTYPE_RANGED + 0.00f, // INVTYPE_CLOAK + 0.00f, // INVTYPE_2HWEAPON + 0.00f, // INVTYPE_BAG + 0.00f, // INVTYPE_TABARD + 1.00f, // INVTYPE_ROBE + 0.00f, // INVTYPE_WEAPONMAINHAND + 0.00f, // INVTYPE_WEAPONOFFHAND + 0.00f, // INVTYPE_HOLDABLE + 0.00f, // INVTYPE_AMMO + 0.00f, // INVTYPE_THROWN + 0.00f, // INVTYPE_RANGEDRIGHT + 0.00f, // INVTYPE_QUIVER + 0.00f, // INVTYPE_RELIC + }; - // spell_2 have learning spell - if (itemTemplate.Spells[1].SpellTrigger != ITEM_SPELLTRIGGER_LEARN_SPELL_ID) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format.", entry, 1+1, itemTemplate.Spells[1].SpellTrigger); - itemTemplate.Spells[0].SpellId = 0; - itemTemplate.Spells[1].SpellId = 0; - itemTemplate.Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else if (!itemTemplate.Spells[1].SpellId) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not have an expected spell in spellid_%d in special learning format.", entry, 1+1); - itemTemplate.Spells[0].SpellId = 0; - itemTemplate.Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else if (itemTemplate.Spells[1].SpellId != -1) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemTemplate.Spells[1].SpellId); - if (!spellInfo && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, itemTemplate.Spells[1].SpellId, NULL)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%d)", entry, 1+1, itemTemplate.Spells[1].SpellId); - itemTemplate.Spells[0].SpellId = 0; - itemTemplate.Spells[1].SpellId = 0; - itemTemplate.Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - // allowed only in special format - else if ((itemTemplate.Spells[1].SpellId == 483) || (itemTemplate.Spells[1].SpellId == 55884)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has broken spell in spellid_%d (%d)", entry, 1+1, itemTemplate.Spells[1].SpellId); - itemTemplate.Spells[0].SpellId = 0; - itemTemplate.Spells[1].SpellId = 0; - itemTemplate.Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - } + static float const weaponMultipliers[MAX_ITEM_SUBCLASS_WEAPON] = + { + 0.89f, // ITEM_SUBCLASS_WEAPON_AXE + 1.03f, // ITEM_SUBCLASS_WEAPON_AXE2 + 0.77f, // ITEM_SUBCLASS_WEAPON_BOW + 0.77f, // ITEM_SUBCLASS_WEAPON_GUN + 0.89f, // ITEM_SUBCLASS_WEAPON_MACE + 1.03f, // ITEM_SUBCLASS_WEAPON_MACE2 + 1.03f, // ITEM_SUBCLASS_WEAPON_POLEARM + 0.89f, // ITEM_SUBCLASS_WEAPON_SWORD + 1.03f, // ITEM_SUBCLASS_WEAPON_SWORD2 + 0.00f, // ITEM_SUBCLASS_WEAPON_Obsolete + 1.03f, // ITEM_SUBCLASS_WEAPON_STAFF + 0.00f, // ITEM_SUBCLASS_WEAPON_EXOTIC + 0.00f, // ITEM_SUBCLASS_WEAPON_EXOTIC2 + 0.64f, // ITEM_SUBCLASS_WEAPON_FIST_WEAPON + 0.00f, // ITEM_SUBCLASS_WEAPON_MISCELLANEOUS + 0.64f, // ITEM_SUBCLASS_WEAPON_DAGGER + 0.64f, // ITEM_SUBCLASS_WEAPON_THROWN + 0.00f, // ITEM_SUBCLASS_WEAPON_SPEAR + 0.77f, // ITEM_SUBCLASS_WEAPON_CROSSBOW + 0.64f, // ITEM_SUBCLASS_WEAPON_WAND + 0.64f, // ITEM_SUBCLASS_WEAPON_FISHING_POLE + }; - // spell_3*, spell_4*, spell_5* is empty - for (uint8 j = 2; j < MAX_ITEM_PROTO_SPELLS; ++j) - { - if (itemTemplate.Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)", entry, j+1, itemTemplate.Spells[j].SpellTrigger); - itemTemplate.Spells[j].SpellId = 0; - itemTemplate.Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else if (itemTemplate.Spells[j].SpellId != 0) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong spell in spellid_%d (%d) for learning special format", entry, j+1, itemTemplate.Spells[j].SpellId); - itemTemplate.Spells[j].SpellId = 0; - } - } - } - // normal spell list - else - { - for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j) - { - if (itemTemplate.Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || itemTemplate.Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)", entry, j+1, itemTemplate.Spells[j].SpellTrigger); - itemTemplate.Spells[j].SpellId = 0; - itemTemplate.Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } + float levelPenalty = 1.0f; + if (itemLevel <= 28) + levelPenalty = 0.966f - float(28u - itemLevel) / 54.0f; - if (itemTemplate.Spells[j].SpellId && itemTemplate.Spells[j].SpellId != -1) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemTemplate.Spells[j].SpellId); - if (!spellInfo && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, itemTemplate.Spells[j].SpellId, NULL)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%d)", entry, j+1, itemTemplate.Spells[j].SpellId); - itemTemplate.Spells[j].SpellId = 0; - } - // allowed only in special format - else if ((itemTemplate.Spells[j].SpellId == 483) || (itemTemplate.Spells[j].SpellId == 55884)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has broken spell in spellid_%d (%d)", entry, j+1, itemTemplate.Spells[j].SpellId); - itemTemplate.Spells[j].SpellId = 0; - } - } - } - } + if (itemClass == ITEM_CLASS_ARMOR) + { + if (inventoryType > INVTYPE_ROBE) + return 0; - if (itemTemplate.Bonding >= MAX_BIND_TYPE) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Bonding value (%u)", entry, itemTemplate.Bonding); + return 5 * uint32(23.0f * qualityMultipliers[quality] * armorMultipliers[inventoryType] * levelPenalty + 0.5f); + } - if (itemTemplate.PageText && !GetPageText(itemTemplate.PageText)) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has non existing first page (Id:%u)", entry, itemTemplate.PageText); + return 5 * uint32(17.0f * qualityMultipliers[quality] * weaponMultipliers[itemSubClass] * levelPenalty + 0.5f); +}; - if (itemTemplate.LockID && !sLockStore.LookupEntry(itemTemplate.LockID)) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong LockID (%u)", entry, itemTemplate.LockID); +void FillDisenchantFields(uint32* disenchantID, uint32* requiredDisenchantSkill, ItemTemplate const& itemTemplate) +{ + *disenchantID = 0; + *(int32*)requiredDisenchantSkill = -1; + if ((itemTemplate.Flags & (ITEM_PROTO_FLAG_CONJURED | ITEM_PROTO_FLAG_UNK6)) || + itemTemplate.Bonding == BIND_QUEST_ITEM || itemTemplate.Area || itemTemplate.Map || + itemTemplate.Stackable > 1 || + itemTemplate.Quality < ITEM_QUALITY_UNCOMMON || itemTemplate.Quality > ITEM_QUALITY_EPIC || + !(itemTemplate.Class == ITEM_CLASS_ARMOR || itemTemplate.Class == ITEM_CLASS_WEAPON) || + !(Item::GetSpecialPrice(&itemTemplate) || sItemCurrencyCostStore.LookupEntry(itemTemplate.ItemId))) + return; - if (itemTemplate.Sheath >= MAX_SHEATHETYPE) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Sheath (%u)", entry, itemTemplate.Sheath); - itemTemplate.Sheath = SHEATHETYPE_NONE; - } + for (uint32 i = 0; i < sItemDisenchantLootStore.GetNumRows(); ++i) + { + ItemDisenchantLootEntry const* disenchant = sItemDisenchantLootStore.LookupEntry(i); + if (!disenchant) + continue; - if (itemTemplate.RandomProperty) + if (disenchant->ItemClass == itemTemplate.Class && + disenchant->ItemQuality == itemTemplate.Quality && + disenchant->MinItemLevel <= itemTemplate.ItemLevel && + disenchant->MaxItemLevel >= itemTemplate.ItemLevel) { - // To be implemented later - if (itemTemplate.RandomProperty == -1) - itemTemplate.RandomProperty = 0; - - else if (!sItemRandomPropertiesStore.LookupEntry(GetItemEnchantMod(itemTemplate.RandomProperty))) + if (disenchant->Id == 60 || disenchant->Id == 61) // epic item disenchant ilvl range 66-99 (classic) { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has unknown (wrong or not listed in `item_enchantment_template`) RandomProperty (%u)", entry, itemTemplate.RandomProperty); - itemTemplate.RandomProperty = 0; + if (itemTemplate.RequiredLevel > 60 || itemTemplate.RequiredSkillRank > 300) + continue; // skip to epic item disenchant ilvl range 90-199 (TBC) } - } - - if (itemTemplate.RandomSuffix && !sItemRandomSuffixStore.LookupEntry(GetItemEnchantMod(itemTemplate.RandomSuffix))) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong RandomSuffix (%u)", entry, itemTemplate.RandomSuffix); - itemTemplate.RandomSuffix = 0; - } - - if (itemTemplate.ItemSet && !sItemSetStore.LookupEntry(itemTemplate.ItemSet)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) have wrong ItemSet (%u)", entry, itemTemplate.ItemSet); - itemTemplate.ItemSet = 0; - } - - if (itemTemplate.Area && !GetAreaEntryByAreaID(itemTemplate.Area)) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Area (%u)", entry, itemTemplate.Area); - - if (itemTemplate.Map && !sMapStore.LookupEntry(itemTemplate.Map)) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Map (%u)", entry, itemTemplate.Map); - - if (itemTemplate.BagFamily) - { - // check bits - for (uint32 j = 0; j < sizeof(itemTemplate.BagFamily)*8; ++j) + else if (disenchant->Id == 66 || disenchant->Id == 67) // epic item disenchant ilvl range 90-199 (TBC) { - uint32 mask = 1 << j; - if ((itemTemplate.BagFamily & mask) == 0) + if (itemTemplate.RequiredLevel <= 60 || (itemTemplate.RequiredSkill && itemTemplate.RequiredSkillRank <= 300)) continue; - - ItemBagFamilyEntry const* bf = sItemBagFamilyStore.LookupEntry(j+1); - if (!bf) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has bag family bit set not listed in ItemBagFamily.dbc, remove bit", entry); - itemTemplate.BagFamily &= ~mask; - continue; - } - - if (BAG_FAMILY_MASK_CURRENCY_TOKENS & mask) - { - CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemTemplate.ItemId); - if (!ctEntry) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has currency bag family bit set in BagFamily but not listed in CurrencyTypes.dbc, remove bit", entry); - itemTemplate.BagFamily &= ~mask; - } - } } - } - - if (itemTemplate.TotemCategory && !sTotemCategoryStore.LookupEntry(itemTemplate.TotemCategory)) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong TotemCategory (%u)", entry, itemTemplate.TotemCategory); - for (uint8 j = 0; j < MAX_ITEM_PROTO_SOCKETS; ++j) - { - if (itemTemplate.Socket[j].Color && (itemTemplate.Socket[j].Color & SOCKET_COLOR_ALL) != itemTemplate.Socket[j].Color) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong socketColor_%d (%u)", entry, j+1, itemTemplate.Socket[j].Color); - itemTemplate.Socket[j].Color = 0; - } + *disenchantID = disenchant->Id; + *requiredDisenchantSkill = disenchant->RequiredDisenchantSkill; + return; } + } +} - if (itemTemplate.GemProperties && !sGemPropertiesStore.LookupEntry(itemTemplate.GemProperties)) - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong GemProperties (%u)", entry, itemTemplate.GemProperties); - - if (itemTemplate.FoodType >= MAX_PET_DIET) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong FoodType value (%u)", entry, itemTemplate.FoodType); - itemTemplate.FoodType = 0; - } +void ObjectMgr::LoadItemTemplates() +{ + uint32 oldMSTime = getMSTime(); + uint32 sparseCount = 0; + uint32 dbCount = 0; - if (itemTemplate.ItemLimitCategory && !sItemLimitCategoryStore.LookupEntry(itemTemplate.ItemLimitCategory)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong LimitCategory value (%u)", entry, itemTemplate.ItemLimitCategory); - itemTemplate.ItemLimitCategory = 0; - } + for (uint32 itemId = 0; itemId < sItemSparseStore.GetNumRows(); ++itemId) + { + ItemSparseEntry const* sparse = sItemSparseStore.LookupEntry(itemId); + ItemEntry const* db2Data = sItemStore.LookupEntry(itemId); + if (!sparse || !db2Data) + continue; - if (itemTemplate.HolidayId && !sHolidaysStore.LookupEntry(itemTemplate.HolidayId)) - { - TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong HolidayId value (%u)", entry, itemTemplate.HolidayId); - itemTemplate.HolidayId = 0; - } + ItemTemplate& itemTemplate = _itemTemplateStore[itemId]; + + itemTemplate.ItemId = itemId; + itemTemplate.Class = db2Data->Class; + itemTemplate.SubClass = db2Data->SubClass; + itemTemplate.SoundOverrideSubclass = db2Data->SoundOverrideSubclass; + itemTemplate.Name1 = sparse->Name->Str[sWorld->GetDefaultDbcLocale()]; + itemTemplate.DisplayInfoID = db2Data->DisplayId; + itemTemplate.Quality = sparse->Quality; + itemTemplate.Flags = sparse->Flags; + itemTemplate.Flags2 = sparse->Flags2; + itemTemplate.Unk430_1 = sparse->Unk430_1; + itemTemplate.Unk430_2 = sparse->Unk430_2; + itemTemplate.BuyCount = std::max(sparse->BuyCount, 1u); + itemTemplate.BuyPrice = sparse->BuyPrice; + itemTemplate.SellPrice = sparse->SellPrice; + itemTemplate.InventoryType = db2Data->InventoryType; + itemTemplate.AllowableClass = sparse->AllowableClass; + itemTemplate.AllowableRace = sparse->AllowableRace; + itemTemplate.ItemLevel = sparse->ItemLevel; + itemTemplate.RequiredLevel = sparse->RequiredLevel; + itemTemplate.RequiredSkill = sparse->RequiredSkill; + itemTemplate.RequiredSkillRank = sparse->RequiredSkillRank; + itemTemplate.RequiredSpell = sparse->RequiredSpell; + itemTemplate.RequiredHonorRank = sparse->RequiredHonorRank; + itemTemplate.RequiredCityRank = sparse->RequiredCityRank; + itemTemplate.RequiredReputationFaction = sparse->RequiredReputationFaction; + itemTemplate.RequiredReputationRank = sparse->RequiredReputationRank; + itemTemplate.MaxCount = sparse->MaxCount; + itemTemplate.Stackable = sparse->Stackable; + itemTemplate.ContainerSlots = sparse->ContainerSlots; + for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + { + itemTemplate.ItemStat[i].ItemStatType = sparse->ItemStatType[i]; + itemTemplate.ItemStat[i].ItemStatValue = sparse->ItemStatValue[i]; + itemTemplate.ItemStat[i].ItemStatUnk1 = sparse->ItemStatUnk1[i]; + itemTemplate.ItemStat[i].ItemStatUnk2 = sparse->ItemStatUnk2[i]; + } + + itemTemplate.ScalingStatDistribution = sparse->ScalingStatDistribution; + + // cache item damage + FillItemDamageFields(&itemTemplate.DamageMin, &itemTemplate.DamageMax, &itemTemplate.DPS, sparse->ItemLevel, + db2Data->Class, db2Data->SubClass, sparse->Quality, sparse->Delay, sparse->StatScalingFactor, + sparse->InventoryType, sparse->Flags2); + + itemTemplate.DamageType = sparse->DamageType; + itemTemplate.Armor = FillItemArmor(sparse->ItemLevel, db2Data->Class, db2Data->SubClass, sparse->Quality, sparse->InventoryType); + itemTemplate.Delay = sparse->Delay; + itemTemplate.RangedModRange = sparse->RangedModRange; + for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) + { + itemTemplate.Spells[i].SpellId = sparse->SpellId[i]; + itemTemplate.Spells[i].SpellTrigger = sparse->SpellTrigger[i]; + itemTemplate.Spells[i].SpellCharges = sparse->SpellCharges[i]; + itemTemplate.Spells[i].SpellCooldown = sparse->SpellCooldown[i]; + itemTemplate.Spells[i].SpellCategory = sparse->SpellCategory[i]; + itemTemplate.Spells[i].SpellCategoryCooldown = sparse->SpellCategoryCooldown[i]; + } + + itemTemplate.SpellPPMRate = 0.0f; + itemTemplate.Bonding = sparse->Bonding; + itemTemplate.Description = sparse->Description->Str[sWorld->GetDefaultDbcLocale()]; + itemTemplate.PageText = sparse->PageText; + itemTemplate.LanguageID = sparse->LanguageID; + itemTemplate.PageMaterial = sparse->PageMaterial; + itemTemplate.StartQuest = sparse->StartQuest; + itemTemplate.LockID = sparse->LockID; + itemTemplate.Material = sparse->Material; + itemTemplate.Sheath = sparse->Sheath; + itemTemplate.RandomProperty = sparse->RandomProperty; + itemTemplate.RandomSuffix = sparse->RandomSuffix; + itemTemplate.ItemSet = sparse->ItemSet; + itemTemplate.MaxDurability = FillMaxDurability(db2Data->Class, db2Data->SubClass, sparse->InventoryType, sparse->Quality, sparse->ItemLevel); + itemTemplate.Area = sparse->Area; + itemTemplate.Map = sparse->Map; + itemTemplate.BagFamily = sparse->BagFamily; + itemTemplate.TotemCategory = sparse->TotemCategory; + for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) + { + itemTemplate.Socket[i].Color = sparse->Color[i]; + itemTemplate.Socket[i].Content = sparse->Content[i]; + } + + itemTemplate.socketBonus = sparse->SocketBonus; + itemTemplate.GemProperties = sparse->GemProperties; + FillDisenchantFields(&itemTemplate.DisenchantID, &itemTemplate.RequiredDisenchantSkill, itemTemplate); + + itemTemplate.ArmorDamageModifier = sparse->ArmorDamageModifier; + itemTemplate.Duration = sparse->Duration; + itemTemplate.ItemLimitCategory = sparse->ItemLimitCategory; + itemTemplate.HolidayId = sparse->HolidayId; + itemTemplate.StatScalingFactor = sparse->StatScalingFactor; + itemTemplate.CurrencySubstitutionId = sparse->CurrencySubstitutionId; + itemTemplate.CurrencySubstitutionCount = sparse->CurrencySubstitutionCount; + itemTemplate.ScriptId = 0; + itemTemplate.FoodType = 0; + itemTemplate.MinMoneyLoot = 0; + itemTemplate.MaxMoneyLoot = 0; + ++sparseCount; + } + + // Load missing items from item_template AND overwrite data from Item-sparse.db2 (item_template is supposed to contain Item-sparse.adb data) + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + QueryResult result = WorldDatabase.Query("SELECT entry, Class, SubClass, SoundOverrideSubclass, Name, DisplayId, Quality, Flags, FlagsExtra, Unk430_1, Unk430_2, BuyCount, BuyPrice, SellPrice, " + // 14 15 16 17 18 19 20 21 + "InventoryType, AllowableClass, AllowableRace, ItemLevel, RequiredLevel, RequiredSkill, RequiredSkillRank, RequiredSpell, " + // 22 23 24 25 26 27 28 + "RequiredHonorRank, RequiredCityRank, RequiredReputationFaction, RequiredReputationRank, MaxCount, Stackable, ContainerSlots, " + // 29 30 31 32 33 34 35 36 + "stat_type1, stat_value1, stat_unk1_1, stat_unk2_1, stat_type2, stat_value2, stat_unk1_2, stat_unk2_2, " + // 37 38 39 40 41 42 43 44 + "stat_type3, stat_value3, stat_unk1_3, stat_unk2_3, stat_type4, stat_value4, stat_unk1_4, stat_unk2_4, " + // 45 46 47 48 49 50 51 52 + "stat_type5, stat_value5, stat_unk1_5, stat_unk2_5, stat_type6, stat_value6, stat_unk1_6, stat_unk2_6, " + // 53 54 55 56 57 58 59 60 + "stat_type7, stat_value7, stat_unk1_7, stat_unk2_7, stat_type8, stat_value8, stat_unk1_8, stat_unk2_8, " + // 61 62 63 64 65 66 67 68 + "stat_type9, stat_value9, stat_unk1_9, stat_unk2_9, stat_type10, stat_value10, stat_unk1_10, stat_unk2_10, " + // 69 70 71 72 + "ScalingStatDistribution, DamageType, Delay, RangedModRange, " + // 73 74 75 76 77 78 + "spellid_1, spelltrigger_1, spellcharges_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1, " + // 79 80 81 82 83 84 + "spellid_2, spelltrigger_2, spellcharges_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2, " + // 85 86 87 88 89 90 + "spellid_3, spelltrigger_3, spellcharges_3, spellcooldown_3, spellcategory_3, spellcategorycooldown_3, " + // 91 92 93 94 95 96 + "spellid_4, spelltrigger_4, spellcharges_4, spellcooldown_4, spellcategory_4, spellcategorycooldown_4, " + // 97 98 99 100 101 102 + "spellid_5, spelltrigger_5, spellcharges_5, spellcooldown_5, spellcategory_5, spellcategorycooldown_5, " + // 103 104 105 106 107 108 109 110 + "Bonding, Description, PageText, LanguageID, PageMaterial, StartQuest, LockID, Material, " + // 111 112 113 114 115 116 117 118 + "Sheath, RandomProperty, RandomSuffix, ItemSet, Area, Map, BagFamily, TotemCategory, " + // 119 120 121 122 123 124 125 + "SocketColor_1, SocketContent_1, SocketColor_2, SocketContent_2, SocketColor_3, SocketContent_3, SocketBonus, " + // 126 127 128 129 130 131 + "GemProperties, ArmorDamageModifier, Duration, ItemLimitCategory, HolidayId, StatScalingFactor, " + // 132 133 + "CurrencySubstitutionId, CurrencySubstitutionCount " + "FROM item_template"); - if (itemTemplate.FlagsCu & ITEM_FLAGS_CU_DURATION_REAL_TIME && !itemTemplate.Duration) + if (result) + { + do { - TC_LOG_ERROR("sql.sql", "Item (Entry %u) has flag ITEM_FLAGS_CU_DURATION_REAL_TIME but it does not have duration limit", entry); - itemTemplate.FlagsCu &= ~ITEM_FLAGS_CU_DURATION_REAL_TIME; - } - - ++count; + Field* fields = result->Fetch(); + uint32 itemId = fields[0].GetUInt32(); + if (_itemTemplateStore.find(itemId) != _itemTemplateStore.end()) + --sparseCount; + + ItemTemplate& itemTemplate = _itemTemplateStore[itemId]; + + itemTemplate.ItemId = itemId; + itemTemplate.Class = uint32(fields[1].GetUInt8()); + itemTemplate.SubClass = uint32(fields[2].GetUInt8()); + itemTemplate.SoundOverrideSubclass = fields[3].GetInt32(); + itemTemplate.Name1 = fields[4].GetString(); + itemTemplate.DisplayInfoID = fields[5].GetUInt32(); + itemTemplate.Quality = uint32(fields[6].GetUInt8()); + itemTemplate.Flags = fields[7].GetUInt32(); + itemTemplate.Flags2 = fields[8].GetUInt32(); + itemTemplate.Unk430_1 = fields[9].GetFloat(); + itemTemplate.Unk430_2 = fields[10].GetFloat(); + itemTemplate.BuyCount = uint32(fields[11].GetUInt8()); + itemTemplate.BuyPrice = int32(fields[12].GetInt64()); + itemTemplate.SellPrice = fields[13].GetUInt32(); + + itemTemplate.InventoryType = uint32(fields[14].GetUInt8()); + itemTemplate.AllowableClass = fields[15].GetInt32(); + itemTemplate.AllowableRace = fields[16].GetInt32(); + itemTemplate.ItemLevel = uint32(fields[17].GetUInt16()); + itemTemplate.RequiredLevel = uint32(fields[18].GetUInt8()); + itemTemplate.RequiredSkill = uint32(fields[19].GetUInt16()); + itemTemplate.RequiredSkillRank = uint32(fields[20].GetUInt16()); + itemTemplate.RequiredSpell = fields[21].GetUInt32(); + itemTemplate.RequiredHonorRank = fields[22].GetUInt32(); + itemTemplate.RequiredCityRank = fields[23].GetUInt32(); + itemTemplate.RequiredReputationFaction = uint32(fields[24].GetUInt16()); + itemTemplate.RequiredReputationRank = uint32(fields[25].GetUInt16()); + itemTemplate.MaxCount = fields[26].GetInt32(); + itemTemplate.Stackable = fields[27].GetInt32(); + itemTemplate.ContainerSlots = uint32(fields[28].GetUInt8()); + for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + { + itemTemplate.ItemStat[i].ItemStatType = uint32(fields[29 + i * 4 + 0].GetUInt8()); + itemTemplate.ItemStat[i].ItemStatValue = int32(fields[29 + i * 4 + 1].GetInt16()); + itemTemplate.ItemStat[i].ItemStatUnk1 = fields[29 + i * 4 + 2].GetInt32(); + itemTemplate.ItemStat[i].ItemStatUnk2 = fields[29 + i * 4 + 3].GetInt32(); + } + + itemTemplate.ScalingStatDistribution = uint32(fields[69].GetUInt16()); + + // cache item damage + FillItemDamageFields(&itemTemplate.DamageMin, &itemTemplate.DamageMax, &itemTemplate.DPS, itemTemplate.ItemLevel, + itemTemplate.Class, itemTemplate.SubClass, itemTemplate.Quality, fields[71].GetUInt16(), + fields[131].GetFloat(), itemTemplate.InventoryType, itemTemplate.Flags2); + + itemTemplate.DamageType = fields[70].GetUInt8(); + itemTemplate.Armor = FillItemArmor(itemTemplate.ItemLevel, itemTemplate.Class, + itemTemplate.SubClass, itemTemplate.Quality, + itemTemplate.InventoryType); + + itemTemplate.Delay = fields[71].GetUInt16(); + itemTemplate.RangedModRange = fields[72].GetFloat(); + for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) + { + itemTemplate.Spells[i].SpellId = fields[73 + 6 * i + 0].GetInt32(); + itemTemplate.Spells[i].SpellTrigger = uint32(fields[73 + 6 * i + 1].GetUInt8()); + itemTemplate.Spells[i].SpellCharges = int32(fields[73 + 6 * i + 2].GetInt16()); + itemTemplate.Spells[i].SpellCooldown = fields[73 + 6 * i + 3].GetInt32(); + itemTemplate.Spells[i].SpellCategory = uint32(fields[73 + 6 * i + 4].GetUInt16()); + itemTemplate.Spells[i].SpellCategoryCooldown = fields[73 + 6 * i + 5].GetInt32(); + } + + itemTemplate.SpellPPMRate = 0.0f; + itemTemplate.Bonding = uint32(fields[103].GetUInt8()); + itemTemplate.Description = fields[104].GetString(); + itemTemplate.PageText = fields[105].GetUInt32(); + itemTemplate.LanguageID = uint32(fields[106].GetUInt8()); + itemTemplate.PageMaterial = uint32(fields[107].GetUInt8()); + itemTemplate.StartQuest = fields[108].GetUInt32(); + itemTemplate.LockID = fields[109].GetUInt32(); + itemTemplate.Material = int32(fields[110].GetInt8()); + itemTemplate.Sheath = uint32(fields[111].GetUInt8()); + itemTemplate.RandomProperty = fields[112].GetUInt32(); + itemTemplate.RandomSuffix = fields[113].GetInt32(); + itemTemplate.ItemSet = fields[114].GetUInt32(); + itemTemplate.MaxDurability = FillMaxDurability(itemTemplate.Class, itemTemplate.SubClass, + itemTemplate.InventoryType, itemTemplate.Quality, itemTemplate.ItemLevel); + + itemTemplate.Area = fields[115].GetUInt32(); + itemTemplate.Map = uint32(fields[116].GetUInt16()); + itemTemplate.BagFamily = fields[117].GetUInt32(); + itemTemplate.TotemCategory = fields[118].GetUInt32(); + for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) + { + itemTemplate.Socket[i].Color = uint32(fields[119 + i*2].GetUInt8()); + itemTemplate.Socket[i].Content = fields[119 + i * 2 + 1].GetUInt32(); + } + + itemTemplate.socketBonus = fields[125].GetUInt32(); + itemTemplate.GemProperties = fields[126].GetUInt32(); + FillDisenchantFields(&itemTemplate.DisenchantID, &itemTemplate.RequiredDisenchantSkill, itemTemplate); + + itemTemplate.ArmorDamageModifier = fields[127].GetFloat(); + itemTemplate.Duration = fields[128].GetUInt32(); + itemTemplate.ItemLimitCategory = uint32(fields[129].GetInt16()); + itemTemplate.HolidayId = fields[130].GetUInt32(); + itemTemplate.StatScalingFactor = fields[131].GetFloat(); + itemTemplate.CurrencySubstitutionId = fields[132].GetInt32(); + itemTemplate.CurrencySubstitutionCount = fields[133].GetInt32(); + itemTemplate.ScriptId = 0; + itemTemplate.FoodType = 0; + itemTemplate.MinMoneyLoot = 0; + itemTemplate.MaxMoneyLoot = 0; + ++dbCount; + } while (result->NextRow()); } - while (result->NextRow()); // Check if item templates for DBC referenced character start outfit are present std::set<uint32> notFoundOutfit; @@ -2810,124 +2785,77 @@ void ObjectMgr::LoadItemTemplates() for (std::set<uint32>::const_iterator itr = notFoundOutfit.begin(); itr != notFoundOutfit.end(); ++itr) TC_LOG_ERROR("sql.sql", "Item (Entry: %u) does not exist in `item_template` but is referenced in `CharStartOutfit.dbc`", *itr); - TC_LOG_INFO("server.loading", ">> Loaded %u item templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u item templates from Item-sparse.db2 and %u from database in %u ms", sparseCount, dbCount, GetMSTimeDiffToNow(oldMSTime)); } -ItemTemplate const* ObjectMgr::GetItemTemplate(uint32 entry) -{ - ItemTemplateContainer::const_iterator itr = _itemTemplateStore.find(entry); - if (itr != _itemTemplateStore.end()) - return &(itr->second); - - return NULL; -} - -void ObjectMgr::LoadItemSetNameLocales() +void ObjectMgr::LoadItemTemplateAddon() { uint32 oldMSTime = getMSTime(); + uint32 count = 0; - _itemSetNameLocaleStore.clear(); // need for reload case - - QueryResult result = WorldDatabase.Query("SELECT `entry`, `name_loc1`, `name_loc2`, `name_loc3`, `name_loc4`, `name_loc5`, `name_loc6`, `name_loc7`, `name_loc8` FROM `locales_item_set_names`"); - - if (!result) - return; - - do + QueryResult result = WorldDatabase.Query("SELECT Id, FlagsCu, FoodType, MinMoneyLoot, MaxMoneyLoot, SpellPPMChance FROM item_template_addon"); + if (result) { - Field* fields = result->Fetch(); - - uint32 entry = fields[0].GetUInt32(); - - ItemSetNameLocale& data = _itemSetNameLocaleStore[entry]; - - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) - AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.Name); - } while (result->NextRow()); + do + { + Field* fields = result->Fetch(); + uint32 itemId = fields[0].GetUInt32(); + if (!GetItemTemplate(itemId)) + { + TC_LOG_ERROR("sql.sql", "Item %u specified in `item_template_addon` does not exist, skipped.", itemId); + continue; + } - TC_LOG_INFO("server.loading", ">> Loaded " UI64FMTD " Item set name locale strings in %u ms", uint64(_itemSetNameLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); + uint32 minMoneyLoot = fields[3].GetUInt32(); + uint32 maxMoneyLoot = fields[4].GetUInt32(); + if (minMoneyLoot > maxMoneyLoot) + { + TC_LOG_ERROR("sql.sql", "Minimum money loot specified in `item_template_addon` for item %u was greater than maximum amount, swapping.", itemId); + std::swap(minMoneyLoot, maxMoneyLoot); + } + ItemTemplate& itemTemplate = _itemTemplateStore[itemId]; + itemTemplate.FlagsCu = fields[1].GetUInt32(); + itemTemplate.FoodType = fields[2].GetUInt8(); + itemTemplate.MinMoneyLoot = minMoneyLoot; + itemTemplate.MaxMoneyLoot = maxMoneyLoot; + itemTemplate.SpellPPMRate = fields[5].GetFloat(); + ++count; + } while (result->NextRow()); + } + TC_LOG_INFO("server.loading", ">> Loaded %u item addon templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadItemSetNames() +void ObjectMgr::LoadItemScriptNames() { uint32 oldMSTime = getMSTime(); - - _itemSetNameStore.clear(); // needed for reload case - - std::set<uint32> itemSetItems; - - // fill item set member ids - for (uint32 entryId = 0; entryId < sItemSetStore.GetNumRows(); ++entryId) - { - ItemSetEntry const* setEntry = sItemSetStore.LookupEntry(entryId); - if (!setEntry) - continue; - - for (uint32 i = 0; i < MAX_ITEM_SET_ITEMS; ++i) - if (setEntry->itemId[i]) - itemSetItems.insert(setEntry->itemId[i]); - } - - // 0 1 2 - QueryResult result = WorldDatabase.Query("SELECT `entry`, `name`, `InventoryType` FROM `item_set_names`"); - - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 item set names. DB table `item_set_names` is empty."); - return; - } - - _itemSetNameStore.rehash(result->GetRowCount()); uint32 count = 0; - do - { - Field* fields = result->Fetch(); - - uint32 entry = fields[0].GetUInt32(); - if (itemSetItems.find(entry) == itemSetItems.end()) - { - TC_LOG_ERROR("sql.sql", "Item set name (Entry: %u) not found in ItemSet.dbc, data useless.", entry); - continue; - } - - ItemSetNameEntry &data = _itemSetNameStore[entry]; - data.name = fields[1].GetString(); - - uint32 invType = fields[2].GetUInt8(); - if (invType >= MAX_INVTYPE) - { - TC_LOG_ERROR("sql.sql", "Item set name (Entry: %u) has wrong InventoryType value (%u)", entry, invType); - invType = INVTYPE_NON_EQUIP; - } - - data.InventoryType = invType; - itemSetItems.erase(entry); - ++count; - } while (result->NextRow()); - - if (!itemSetItems.empty()) + QueryResult result = WorldDatabase.Query("SELECT Id, ScriptName FROM item_script_names"); + if (result) { - ItemTemplate const* pProto; - for (std::set<uint32>::iterator itr = itemSetItems.begin(); itr != itemSetItems.end(); ++itr) + do { - uint32 entry = *itr; - // add data from item_template if available - pProto = sObjectMgr->GetItemTemplate(entry); - if (pProto) + Field* fields = result->Fetch(); + uint32 itemId = fields[0].GetUInt32(); + if (!GetItemTemplate(itemId)) { - TC_LOG_ERROR("sql.sql", "Item set part (Entry: %u) does not have entry in `item_set_names`, adding data from `item_template`.", entry); - ItemSetNameEntry &data = _itemSetNameStore[entry]; - data.name = pProto->Name1; - data.InventoryType = pProto->InventoryType; - ++count; + TC_LOG_ERROR("sql.sql", "Item %u specified in `item_script_names` does not exist, skipped.", itemId); + continue; } - else - TC_LOG_ERROR("sql.sql", "Item set part (Entry: %u) does not have entry in `item_set_names`, set will not display properly.", entry); - } + + _itemTemplateStore[itemId].ScriptId = GetScriptId(fields[1].GetCString()); + ++count; + } while (result->NextRow()); } - TC_LOG_INFO("server.loading", ">> Loaded %u item set names in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u item script names in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} +ItemTemplate const* ObjectMgr::GetItemTemplate(uint32 entry) +{ + ItemTemplateContainer::const_iterator itr = _itemTemplateStore.find(entry); + if (itr != _itemTemplateStore.end()) + return &(itr->second); + return NULL; } void ObjectMgr::LoadVehicleTemplateAccessories() @@ -3459,6 +3387,61 @@ void ObjectMgr::LoadPlayerInfo() } } + // Load playercreate cast spell + TC_LOG_INFO("server.loading", "Loading Player Create Cast Spell Data..."); + { + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.PQuery("SELECT raceMask, classMask, spell FROM playercreateinfo_cast_spell"); + + if (!result) + TC_LOG_ERROR("server.loading", ">> Loaded 0 player create cast spells. DB table `playercreateinfo_cast_spell` is empty."); + else + { + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + uint32 raceMask = fields[0].GetUInt32(); + uint32 classMask = fields[1].GetUInt32(); + uint32 spellId = fields[2].GetUInt32(); + + if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) + { + TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_cast_spell` table, ignoring.", raceMask); + continue; + } + + if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE)) + { + TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_cast_spell` table, ignoring.", classMask); + continue; + } + + for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex) + { + if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask)) + { + for (uint32 classIndex = CLASS_WARRIOR; classIndex < MAX_CLASSES; ++classIndex) + { + if (classMask == 0 || ((1 << (classIndex - 1)) & classMask)) + { + if (PlayerInfo* info = _playerInfo[raceIndex][classIndex]) + { + info->castSpells.push_back(spellId); + ++count; + } + } + } + } + } + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u player create cast spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + } + } + // Load playercreate actions TC_LOG_INFO("server.loading", "Loading Player Create Action Data..."); { @@ -3504,88 +3487,6 @@ void ObjectMgr::LoadPlayerInfo() } } - // Loading levels data (class only dependent) - TC_LOG_INFO("server.loading", "Loading Player Create Level HP/Mana Data..."); - { - uint32 oldMSTime = getMSTime(); - - // 0 1 2 3 - QueryResult result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats"); - - if (!result) - { - TC_LOG_ERROR("server.loading", ">> Loaded 0 level health/mana definitions. DB table `player_classlevelstats` is empty."); - exit(1); - } - - uint32 count = 0; - - do - { - Field* fields = result->Fetch(); - - uint32 current_class = fields[0].GetUInt8(); - if (current_class >= MAX_CLASSES) - { - TC_LOG_ERROR("sql.sql", "Wrong class %u in `player_classlevelstats` table, ignoring.", current_class); - continue; - } - - uint8 current_level = fields[1].GetUInt8(); // Can't be > than STRONG_MAX_LEVEL (hardcoded level maximum) due to var type - if (current_level > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - TC_LOG_INFO("misc", "Unused (> MaxPlayerLevel in worldserver.conf) level %u in `player_classlevelstats` table, ignoring.", current_level); - ++count; // make result loading percent "expected" correct in case disabled detail mode for example. - continue; - } - - PlayerClassInfo* info = _playerClassInfo[current_class]; - if (!info) - { - info = new PlayerClassInfo(); - info->levelInfo = new PlayerClassLevelInfo[sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)]; - _playerClassInfo[current_class] = info; - } - - PlayerClassLevelInfo& levelInfo = info->levelInfo[current_level-1]; - - levelInfo.basehealth = fields[2].GetUInt16(); - levelInfo.basemana = fields[3].GetUInt16(); - - ++count; - } - while (result->NextRow()); - - // Fill gaps and check integrity - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - { - // skip non existed classes - if (!sChrClassesStore.LookupEntry(class_)) - continue; - - PlayerClassInfo* pClassInfo = _playerClassInfo[class_]; - - // fatal error if no level 1 data - if (!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0) - { - TC_LOG_ERROR("sql.sql", "Class %i Level 1 does not have health/mana data!", class_); - exit(1); - } - - // fill level gaps - for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - { - if (pClassInfo->levelInfo[level].basehealth == 0) - { - TC_LOG_ERROR("sql.sql", "Class %i Level %i does not have health/mana data. Using stats data of level %i.", class_, level + 1, level); - pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level - 1]; - } - } - } - - TC_LOG_INFO("server.loading", ">> Loaded %u level health/mana definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - } - // Loading levels data (class/race dependent) TC_LOG_INFO("server.loading", "Loading Player Create Level Stats Data..."); { @@ -3672,6 +3573,10 @@ void ObjectMgr::LoadPlayerInfo() if (sWorld->getIntConfig(CONFIG_EXPANSION) < EXPANSION_WRATH_OF_THE_LICH_KING && class_ == CLASS_DEATH_KNIGHT) continue; + // skip expansion races if not playing with expansion + if (sWorld->getIntConfig(CONFIG_EXPANSION) < EXPANSION_CATACLYSM && (race == RACE_GOBLIN || race == RACE_WORGEN)) + continue; + // fatal error if no level 1 data if (!info->levelInfo || info->levelInfo[0].stats[0] == 0) { @@ -3752,17 +3657,25 @@ void ObjectMgr::LoadPlayerInfo() } } -void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint8 level, PlayerClassLevelInfo* info) const +void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint8 level, uint32& baseHP, uint32& baseMana) const { if (level < 1 || class_ >= MAX_CLASSES) return; - PlayerClassInfo const* pInfo = _playerClassInfo[class_]; - if (level > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) level = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); - *info = pInfo->levelInfo[level-1]; + GtOCTBaseHPByClassEntry const* hp = sGtOCTBaseHPByClassStore.LookupEntry((class_-1) * GT_MAX_LEVEL + level-1); + GtOCTBaseMPByClassEntry const* mp = sGtOCTBaseMPByClassStore.LookupEntry((class_-1) * GT_MAX_LEVEL + level-1); + + if (!hp || !mp) + { + TC_LOG_ERROR("misc", "Tried to get non-existant Class-Level combination data for base hp/mp. Class %u Level %u", class_, level); + return; + } + + baseHP = uint32(hp->ratio); + baseMana = uint32(mp->ratio); } void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint8 level, PlayerLevelInfo* info) const @@ -3874,30 +3787,34 @@ void ObjectMgr::LoadQuests() "RequiredFactionId1, RequiredFactionId2, RequiredFactionValue1, RequiredFactionValue2, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, " // 21 22 23 24 25 26 27 28 29 30 31 "PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestIdChain, RewardXPId, RewardOrRequiredMoney, RewardMoneyMaxLevel, RewardSpell, RewardSpellCast, RewardHonor, RewardHonorMultiplier, " - // 32 33 34 35 36 37 38 39 40 41 42 - "RewardMailTemplateId, RewardMailDelay, SourceItemId, SourceItemCount, SourceSpellId, Flags, SpecialFlags, RewardTitleId, RequiredPlayerKills, RewardTalents, RewardArenaPoints, " - // 43 44 45 46 47 48 49 50 - "RewardItemId1, RewardItemId2, RewardItemId3, RewardItemId4, RewardItemCount1, RewardItemCount2, RewardItemCount3, RewardItemCount4, " - // 51 52 53 54 55 56 57 58 59 60 61 62 + // 32 33 34 35 36 37 38 39 40 41 42 43 + "RewardMailTemplateId, RewardMailDelay, SourceItemId, SourceItemCount, SourceSpellId, Flags, SpecialFlags, MinimapTargetMark, RewardTitleId, RequiredPlayerKills, RewardTalents, RewardArenaPoints, " + // 44 45 46 47 48 49 50 51 52 53 54 55 56 + "RewardSkillId, RewardSkillPoints, RewardReputationMask, QuestGiverPortrait, QuestTurnInPortrait, RewardItemId1, RewardItemId2, RewardItemId3, RewardItemId4, RewardItemCount1, RewardItemCount2, RewardItemCount3, RewardItemCount4, " + // 57 58 59 60 61 62 63 64 65 66 67 68 "RewardChoiceItemId1, RewardChoiceItemId2, RewardChoiceItemId3, RewardChoiceItemId4, RewardChoiceItemId5, RewardChoiceItemId6, RewardChoiceItemCount1, RewardChoiceItemCount2, RewardChoiceItemCount3, RewardChoiceItemCount4, RewardChoiceItemCount5, RewardChoiceItemCount6, " - // 63 64 65 66 67 68 69 70 71 72 + // 69 70 71 72 73 74 75 76 77 78 "RewardFactionId1, RewardFactionId2, RewardFactionId3, RewardFactionId4, RewardFactionId5, RewardFactionValueId1, RewardFactionValueId2, RewardFactionValueId3, RewardFactionValueId4, RewardFactionValueId5, " - // 73 74 75 76 77 + // 79 80 81 82 83 "RewardFactionValueIdOverride1, RewardFactionValueIdOverride2, RewardFactionValueIdOverride3, RewardFactionValueIdOverride4, RewardFactionValueIdOverride5, " - // 78 79 80 81 - "PointMapId, PointX, PointY, PointOption, " - // 82 83 84 85 86 87 88 - "Title, Objectives, Details, EndText, OfferRewardText, RequestItemsText, CompletedText, " - // 89 90 91 92 93 94 95 96 + // 84 85 86 87 88 89 90 91 92 93 94 + "PointMapId, PointX, PointY, PointOption, Title, Objectives, Details, EndText, CompletedText, OfferRewardText, RequestItemsText, " + // 95 96 97 98 99 100 101 102 "RequiredNpcOrGo1, RequiredNpcOrGo2, RequiredNpcOrGo3, RequiredNpcOrGo4, RequiredNpcOrGoCount1, RequiredNpcOrGoCount2, RequiredNpcOrGoCount3, RequiredNpcOrGoCount4, " - // 97 98 99 100 101 102 103 104 + // 103 104 105 106 107 108 109 110 "RequiredSourceItemId1, RequiredSourceItemId2, RequiredSourceItemId3, RequiredSourceItemId4, RequiredSourceItemCount1, RequiredSourceItemCount2, RequiredSourceItemCount3, RequiredSourceItemCount4, " - // 105 106 107 108 109 110 111 112 113 114 115 116 + // 111 112 113 114 115 116 117 118 119 120 121 122 "RequiredItemId1, RequiredItemId2, RequiredItemId3, RequiredItemId4, RequiredItemId5, RequiredItemId6, RequiredItemCount1, RequiredItemCount2, RequiredItemCount3, RequiredItemCount4, RequiredItemCount5, RequiredItemCount6, " - // 117 118 119 120 121 122 123 124 125 126 127 128 129 - "Unknown0, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4, DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4, " - // 130 131 132 133 134 135 136 137 138 139 - "EmoteOnIncomplete, EmoteOnComplete, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4, OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4" + // 123 124 125 126 127 128 129 130 131 132 133 134 135 + "RequiredSpell, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4, RewardCurrencyId1, RewardCurrencyId2, RewardCurrencyId3, RewardCurrencyId4, RewardCurrencyCount1, RewardCurrencyCount2, RewardCurrencyCount3, RewardCurrencyCount4, " + // 136 137 138 139 140 141 142 143 + "RequiredCurrencyId1, RequiredCurrencyId2, RequiredCurrencyId3, RequiredCurrencyId4, RequiredCurrencyCount1, RequiredCurrencyCount2, RequiredCurrencyCount3, RequiredCurrencyCount4, " + // 144 145 146 147 148 149 + "QuestGiverTextWindow, QuestGiverTargetName, QuestTurnTextWindow, QuestTurnTargetName, SoundAccept, SoundTurnIn, " + // 150 151 152 153 154 155 156 157 158 159 + "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4, EmoteOnIncomplete, EmoteOnComplete, " + // 160 161 162 163 164 165 166 167 + "OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4, OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4" " FROM quest_template"); if (!result) { @@ -3925,7 +3842,7 @@ void ObjectMgr::LoadQuests() if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, iter->first, NULL)) continue; - Quest * qinfo = iter->second; + Quest* qinfo = iter->second; // additional quest integrity checks (GO, creature_template and item_template must be loaded already) @@ -3986,6 +3903,12 @@ void ObjectMgr::LoadQuests() } } + if (qinfo->MinLevel == uint32(-1) || qinfo->MinLevel > DEFAULT_MAX_LEVEL) + { + TC_LOG_ERROR("sql.sql", "Quest %u should be disabled because `MinLevel` = %i", qinfo->GetQuestId(), int32(qinfo->MinLevel)); + // no changes needed, sending -1 in SMSG_QUEST_QUERY_RESPONSE is valid + } + // client quest log visual (area case) if (qinfo->ZoneOrSort > 0) { @@ -4029,13 +3952,13 @@ void ObjectMgr::LoadQuests() } // RequiredRaces, can be 0/RACEMASK_ALL_PLAYABLE to allow any race if (qinfo->RequiredRaces) - { + { if (!(qinfo->RequiredRaces & RACEMASK_ALL_PLAYABLE)) { TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable races in `RequiredRaces` (%u), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->RequiredRaces); qinfo->RequiredRaces = 0; } - } + } // RequiredSkillId, can be 0 if (qinfo->RequiredSkillId) { @@ -4195,7 +4118,7 @@ void ObjectMgr::LoadQuests() qinfo->RequiredItemCount[j] = 0; // prevent incorrect work of quest } } - else if (qinfo->RequiredItemCount[j]>0) + else if (qinfo->RequiredItemCount[j] > 0) { TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredItemId%d` = 0 but `RequiredItemCount%d` = %u, quest can't be done.", qinfo->GetQuestId(), j+1, j+1, qinfo->RequiredItemCount[j]); @@ -4427,26 +4350,149 @@ void ObjectMgr::LoadQuests() qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId()); } + for (uint8 j = 0; j < QUEST_REWARD_CURRENCY_COUNT; ++j) + { + if (qinfo->RewardCurrencyId[j]) + { + if (qinfo->RewardCurrencyCount[j] == 0) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardCurrencyId%d` = %u but `RewardCurrencyCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(), j+1, qinfo->RewardCurrencyId[j], j+1); + // no changes, quest can't be done for this requirement + } + + if (!sCurrencyTypesStore.LookupEntry(qinfo->RewardCurrencyId[j])) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardCurrencyId%d` = %u but currency with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(), j+1, qinfo->RewardCurrencyId[j], qinfo->RewardCurrencyId[j]); + qinfo->RewardCurrencyCount[j] = 0; // prevent incorrect work of quest + } + } + else if (qinfo->RewardCurrencyCount[j] > 0) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardCurrencyId%d` = 0 but `RewardCurrencyCount%d` = %u, quest can't be done.", + qinfo->GetQuestId(), j+1, j+1, qinfo->RewardCurrencyCount[j]); + qinfo->RewardCurrencyCount[j] = 0; // prevent incorrect work of quest + } + } + + for (uint8 j = 0; j < QUEST_REQUIRED_CURRENCY_COUNT; ++j) + { + if (qinfo->RequiredCurrencyId[j]) + { + if (qinfo->RequiredCurrencyCount[j] == 0) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredCurrencyId%d` = %u but `RequiredCurrencyCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(), j+1, qinfo->RequiredCurrencyId[j], j+1); + // no changes, quest can't be done for this requirement + } + + if (!sCurrencyTypesStore.LookupEntry(qinfo->RequiredCurrencyId[j])) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredCurrencyId%d` = %u but currency with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(), j+1, qinfo->RequiredCurrencyId[j], qinfo->RequiredCurrencyId[j]); + qinfo->RequiredCurrencyCount[j] = 0; // prevent incorrect work of quest + } + } + else if (qinfo->RequiredCurrencyCount[j] > 0) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredCurrencyId%d` = 0 but `RequiredCurrencyCount%d` = %u, quest can't be done.", + qinfo->GetQuestId(), j+1, j+1, qinfo->RequiredCurrencyCount[j]); + qinfo->RequiredCurrencyCount[j] = 0; // prevent incorrect work of quest + } + } + + if (qinfo->SoundAccept) + { + if (!sSoundEntriesStore.LookupEntry(qinfo->SoundAccept)) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `SoundAccept` = %u but sound %u does not exist, set to 0.", + qinfo->GetQuestId(), qinfo->SoundAccept, qinfo->SoundAccept); + qinfo->SoundAccept = 0; // no sound will be played + } + } + + if (qinfo->SoundTurnIn) + { + if (!sSoundEntriesStore.LookupEntry(qinfo->SoundTurnIn)) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `SoundTurnIn` = %u but sound %u does not exist, set to 0.", + qinfo->GetQuestId(), qinfo->SoundTurnIn, qinfo->SoundTurnIn); + qinfo->SoundTurnIn = 0; // no sound will be played + } + } + + if (qinfo->RequiredSpell > 0) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RequiredSpell); + + if (!spellInfo) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSpell` = %u but spell %u does not exist, quest will not require a spell.", + qinfo->GetQuestId(), qinfo->RequiredSpell, qinfo->RequiredSpell); + qinfo->RequiredSpell = 0; // no spell will be required + } + + else if (!SpellMgr::IsSpellValid(spellInfo)) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSpell` = %u but spell %u is broken, quest will not require a spell.", + qinfo->GetQuestId(), qinfo->RequiredSpell, qinfo->RequiredSpell); + qinfo->RequiredSpell = 0; // no spell will be required + } + + /* Can we require talents? + else if (GetTalentSpellCost(qinfo->RewardSpellCast)) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast); + qinfo->RewardSpellCast = 0; // no spell will be casted on player + } + }*/ + } + + if (qinfo->RewardSkillId) + { + if (!sSkillLineStore.LookupEntry(qinfo->RewardSkillId)) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillId` = %u but this skill does not exist", + qinfo->GetQuestId(), qinfo->RewardSkillId); + } + if (!qinfo->RewardSkillPoints) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillId` = %u but `RewardSkillPoints` is 0", + qinfo->GetQuestId(), qinfo->RewardSkillId); + } + } + + if (qinfo->RewardSkillPoints) + { + if (qinfo->RewardSkillPoints > sWorld->GetConfigMaxSkillValue()) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillPoints` = %u but max possible skill is %u, quest can't be done.", + qinfo->GetQuestId(), qinfo->RewardSkillPoints, sWorld->GetConfigMaxSkillValue()); + // no changes, quest can't be done for this requirement + } + if (!qinfo->RewardSkillId) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillPoints` = %u but `RewardSkillId` is 0", + qinfo->GetQuestId(), qinfo->RewardSkillPoints); + } + } + // fill additional data stores if (qinfo->PrevQuestId) { if (_questTemplates.find(abs(qinfo->GetPrevQuestId())) == _questTemplates.end()) - { TC_LOG_ERROR("sql.sql", "Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId()); - } else - { qinfo->prevQuests.push_back(qinfo->PrevQuestId); - } } if (qinfo->NextQuestId) { QuestMap::iterator qNextItr = _questTemplates.find(abs(qinfo->GetNextQuestId())); if (qNextItr == _questTemplates.end()) - { TC_LOG_ERROR("sql.sql", "Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId()); - } else { int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId()); @@ -4502,14 +4548,14 @@ void ObjectMgr::LoadQuestLocales() _questLocaleStore.clear(); // need for reload case QueryResult result = WorldDatabase.Query("SELECT Id, " - "Title_loc1, Details_loc1, Objectives_loc1, OfferRewardText_loc1, RequestItemsText_loc1, EndText_loc1, CompletedText_loc1, ObjectiveText1_loc1, ObjectiveText2_loc1, ObjectiveText3_loc1, ObjectiveText4_loc1, " - "Title_loc2, Details_loc2, Objectives_loc2, OfferRewardText_loc2, RequestItemsText_loc2, EndText_loc2, CompletedText_loc2, ObjectiveText1_loc2, ObjectiveText2_loc2, ObjectiveText3_loc2, ObjectiveText4_loc2, " - "Title_loc3, Details_loc3, Objectives_loc3, OfferRewardText_loc3, RequestItemsText_loc3, EndText_loc3, CompletedText_loc3, ObjectiveText1_loc3, ObjectiveText2_loc3, ObjectiveText3_loc3, ObjectiveText4_loc3, " - "Title_loc4, Details_loc4, Objectives_loc4, OfferRewardText_loc4, RequestItemsText_loc4, EndText_loc4, CompletedText_loc4, ObjectiveText1_loc4, ObjectiveText2_loc4, ObjectiveText3_loc4, ObjectiveText4_loc4, " - "Title_loc5, Details_loc5, Objectives_loc5, OfferRewardText_loc5, RequestItemsText_loc5, EndText_loc5, CompletedText_loc5, ObjectiveText1_loc5, ObjectiveText2_loc5, ObjectiveText3_loc5, ObjectiveText4_loc5, " - "Title_loc6, Details_loc6, Objectives_loc6, OfferRewardText_loc6, RequestItemsText_loc6, EndText_loc6, CompletedText_loc6, ObjectiveText1_loc6, ObjectiveText2_loc6, ObjectiveText3_loc6, ObjectiveText4_loc6, " - "Title_loc7, Details_loc7, Objectives_loc7, OfferRewardText_loc7, RequestItemsText_loc7, EndText_loc7, CompletedText_loc7, ObjectiveText1_loc7, ObjectiveText2_loc7, ObjectiveText3_loc7, ObjectiveText4_loc7, " - "Title_loc8, Details_loc8, Objectives_loc8, OfferRewardText_loc8, RequestItemsText_loc8, EndText_loc8, CompletedText_loc8, ObjectiveText1_loc8, ObjectiveText2_loc8, ObjectiveText3_loc8, ObjectiveText4_loc8" + "Title_loc1, Details_loc1, Objectives_loc1, OfferRewardText_loc1, RequestItemsText_loc1, EndText_loc1, CompletedText_loc1, ObjectiveText1_loc1, ObjectiveText2_loc1, ObjectiveText3_loc1, ObjectiveText4_loc1, QuestGiverTextWindow_loc1, QuestGiverTargetName_loc1, QuestTurnTextWindow_loc1, QuestTurnTargetName_loc1," + "Title_loc2, Details_loc2, Objectives_loc2, OfferRewardText_loc2, RequestItemsText_loc2, EndText_loc2, CompletedText_loc2, ObjectiveText1_loc2, ObjectiveText2_loc2, ObjectiveText3_loc2, ObjectiveText4_loc2, QuestGiverTextWindow_loc2, QuestGiverTargetName_loc2, QuestTurnTextWindow_loc2, QuestTurnTargetName_loc2," + "Title_loc3, Details_loc3, Objectives_loc3, OfferRewardText_loc3, RequestItemsText_loc3, EndText_loc3, CompletedText_loc3, ObjectiveText1_loc3, ObjectiveText2_loc3, ObjectiveText3_loc3, ObjectiveText4_loc3, QuestGiverTextWindow_loc3, QuestGiverTargetName_loc3, QuestTurnTextWindow_loc3, QuestTurnTargetName_loc3," + "Title_loc4, Details_loc4, Objectives_loc4, OfferRewardText_loc4, RequestItemsText_loc4, EndText_loc4, CompletedText_loc4, ObjectiveText1_loc4, ObjectiveText2_loc4, ObjectiveText3_loc4, ObjectiveText4_loc4, QuestGiverTextWindow_loc4, QuestGiverTargetName_loc4, QuestTurnTextWindow_loc4, QuestTurnTargetName_loc4," + "Title_loc5, Details_loc5, Objectives_loc5, OfferRewardText_loc5, RequestItemsText_loc5, EndText_loc5, CompletedText_loc5, ObjectiveText1_loc5, ObjectiveText2_loc5, ObjectiveText3_loc5, ObjectiveText4_loc5, QuestGiverTextWindow_loc5, QuestGiverTargetName_loc5, QuestTurnTextWindow_loc5, QuestTurnTargetName_loc5," + "Title_loc6, Details_loc6, Objectives_loc6, OfferRewardText_loc6, RequestItemsText_loc6, EndText_loc6, CompletedText_loc6, ObjectiveText1_loc6, ObjectiveText2_loc6, ObjectiveText3_loc6, ObjectiveText4_loc6, QuestGiverTextWindow_loc6, QuestGiverTargetName_loc6, QuestTurnTextWindow_loc6, QuestTurnTargetName_loc6," + "Title_loc7, Details_loc7, Objectives_loc7, OfferRewardText_loc7, RequestItemsText_loc7, EndText_loc7, CompletedText_loc7, ObjectiveText1_loc7, ObjectiveText2_loc7, ObjectiveText3_loc7, ObjectiveText4_loc7, QuestGiverTextWindow_loc7, QuestGiverTargetName_loc7, QuestTurnTextWindow_loc7, QuestTurnTargetName_loc7," + "Title_loc8, Details_loc8, Objectives_loc8, OfferRewardText_loc8, RequestItemsText_loc8, EndText_loc8, CompletedText_loc8, ObjectiveText1_loc8, ObjectiveText2_loc8, ObjectiveText3_loc8, ObjectiveText4_loc8, QuestGiverTextWindow_loc8, QuestGiverTargetName_loc8, QuestTurnTextWindow_loc8, QuestTurnTargetName_loc8" " FROM locales_quest"); if (!result) @@ -4527,16 +4573,21 @@ void ObjectMgr::LoadQuestLocales() { LocaleConstant locale = (LocaleConstant) i; - AddLocaleString(fields[1 + 11 * (i - 1)].GetString(), locale, data.Title); - AddLocaleString(fields[1 + 11 * (i - 1) + 1].GetString(), locale, data.Details); - AddLocaleString(fields[1 + 11 * (i - 1) + 2].GetString(), locale, data.Objectives); - AddLocaleString(fields[1 + 11 * (i - 1) + 3].GetString(), locale, data.OfferRewardText); - AddLocaleString(fields[1 + 11 * (i - 1) + 4].GetString(), locale, data.RequestItemsText); - AddLocaleString(fields[1 + 11 * (i - 1) + 5].GetString(), locale, data.EndText); - AddLocaleString(fields[1 + 11 * (i - 1) + 6].GetString(), locale, data.CompletedText); + AddLocaleString(fields[1 + 15 * (i - 1)].GetString(), locale, data.Title); + AddLocaleString(fields[1 + 15 * (i - 1) + 1].GetString(), locale, data.Details); + AddLocaleString(fields[1 + 15 * (i - 1) + 2].GetString(), locale, data.Objectives); + AddLocaleString(fields[1 + 15 * (i - 1) + 3].GetString(), locale, data.OfferRewardText); + AddLocaleString(fields[1 + 15 * (i - 1) + 4].GetString(), locale, data.RequestItemsText); + AddLocaleString(fields[1 + 15 * (i - 1) + 5].GetString(), locale, data.EndText); + AddLocaleString(fields[1 + 15 * (i - 1) + 6].GetString(), locale, data.CompletedText); for (uint8 k = 0; k < 4; ++k) - AddLocaleString(fields[1 + 11 * (i - 1) + 7 + k].GetString(), locale, data.ObjectiveText[k]); + AddLocaleString(fields[1 + 15 * (i - 1) + 7 + k].GetString(), locale, data.ObjectiveText[k]); + + AddLocaleString(fields[1 + 15 * (i - 1) + 11].GetString(), locale, data.QuestGiverTextWindow); + AddLocaleString(fields[1 + 15 * (i - 1) + 12].GetString(), locale, data.QuestGiverTargetName); + AddLocaleString(fields[1 + 15 * (i - 1) + 13].GetString(), locale, data.QuestTurnTextWindow); + AddLocaleString(fields[1 + 15 * (i - 1) + 14].GetString(), locale, data.QuestTurnTargetName); } } while (result->NextRow()); @@ -4991,7 +5042,7 @@ void ObjectMgr::LoadSpellScriptNames() SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) does not exist.", scriptName, spellId); + TC_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) does not exist.", scriptName, fields[0].GetInt32()); continue; } @@ -5005,7 +5056,6 @@ void ObjectMgr::LoadSpellScriptNames() TC_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) is not first rank of spell.", scriptName, fields[0].GetInt32()); continue; } - while (spellInfo) { _spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, GetScriptId(scriptName))); @@ -5239,7 +5289,7 @@ void ObjectMgr::LoadInstanceEncounters() if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeonEntry(lastEncounterDungeon)) { - TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName[0], lastEncounterDungeon); + TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName, lastEncounterDungeon); continue; } @@ -5248,7 +5298,7 @@ void ObjectMgr::LoadInstanceEncounters() { if (itr != dungeonLastBosses.end()) { - TC_LOG_ERROR("sql.sql", "Table `instance_encounters` specified encounter %u (%s) as last encounter but %u (%s) is already marked as one, skipped!", entry, dungeonEncounter->encounterName[0], itr->second->id, itr->second->encounterName[0]); + TC_LOG_ERROR("sql.sql", "Table `instance_encounters` specified encounter %u (%s) as last encounter but %u (%s) is already marked as one, skipped!", entry, dungeonEncounter->encounterName, itr->second->id, itr->second->encounterName); continue; } @@ -5262,7 +5312,7 @@ void ObjectMgr::LoadInstanceEncounters() CreatureTemplate const* creatureInfo = GetCreatureTemplate(creditEntry); if (!creatureInfo) { - TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid creature (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->encounterName[0]); + TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid creature (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->encounterName); continue; } const_cast<CreatureTemplate*>(creatureInfo)->flags_extra |= CREATURE_FLAG_EXTRA_DUNGEON_BOSS; @@ -5271,17 +5321,32 @@ void ObjectMgr::LoadInstanceEncounters() case ENCOUNTER_CREDIT_CAST_SPELL: if (!sSpellMgr->GetSpellInfo(creditEntry)) { - TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid spell (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->encounterName[0]); + TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid spell (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->encounterName); continue; } break; default: - TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid credit type (%u) for encounter %u (%s), skipped!", creditType, entry, dungeonEncounter->encounterName[0]); + TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid credit type (%u) for encounter %u (%s), skipped!", creditType, entry, dungeonEncounter->encounterName); continue; } - DungeonEncounterList& encounters = _dungeonEncounterStore[MAKE_PAIR32(dungeonEncounter->mapId, dungeonEncounter->difficulty)]; - encounters.push_back(new DungeonEncounter(dungeonEncounter, EncounterCreditType(creditType), creditEntry, lastEncounterDungeon)); + if (dungeonEncounter->difficulty == -1) + { + for (uint32 i = 0; i < MAX_DIFFICULTY; ++i) + { + if (GetMapDifficultyData(dungeonEncounter->mapId, Difficulty(i))) + { + DungeonEncounterList& encounters = _dungeonEncounterStore[MAKE_PAIR32(dungeonEncounter->mapId, i)]; + encounters.push_back(new DungeonEncounter(dungeonEncounter, EncounterCreditType(creditType), creditEntry, lastEncounterDungeon)); + } + } + } + else + { + DungeonEncounterList& encounters = _dungeonEncounterStore[MAKE_PAIR32(dungeonEncounter->mapId, dungeonEncounter->difficulty)]; + encounters.push_back(new DungeonEncounter(dungeonEncounter, EncounterCreditType(creditType), creditEntry, lastEncounterDungeon)); + } + ++count; } while (result->NextRow()); @@ -5470,7 +5535,7 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) bool has_items = fields[4].GetBool(); m->expire_time = time_t(fields[5].GetUInt32()); m->deliver_time = 0; - m->COD = fields[6].GetUInt32(); + m->COD = fields[6].GetUInt64(); m->checked = fields[7].GetUInt8(); m->mailTemplateId = fields[8].GetInt16(); @@ -5686,8 +5751,8 @@ uint32 ObjectMgr::GetNearestTaxiNode(float x, float y, float z, uint32 mapid, ui if (!node || node->map_id != mapid || (!node->MountCreatureID[team == ALLIANCE ? 1 : 0] && node->MountCreatureID[0] != 32981)) // dk flight continue; - uint8 field = (uint8)((i - 1) / 32); - uint32 submask = 1<<((i-1)%32); + uint8 field = (uint8)((i - 1) / 8); + uint32 submask = 1 << ((i-1) % 8); // skip not taxi network nodes if ((sTaxiNodesMask[field] & submask) == 0) @@ -6088,7 +6153,7 @@ void ObjectMgr::LoadAreaTriggerTeleports() uint32 Trigger_ID = fields[0].GetUInt32(); - AreaTrigger at; + AreaTriggerStruct at; at.target_mapId = fields[1].GetUInt16(); at.target_X = fields[2].GetFloat(); @@ -6135,8 +6200,8 @@ void ObjectMgr::LoadAccessRequirements() _accessRequirementStore.clear(); // need for reload case } - // 0 1 2 3 4 5 6 7 8 9 10 - QueryResult result = WorldDatabase.Query("SELECT mapid, difficulty, level_min, level_max, item_level, item, item2, quest_done_A, quest_done_H, completed_achievement, quest_failed_text FROM access_requirement"); + // 0 1 2 3 4 5 6 7 8 9 + QueryResult result = WorldDatabase.Query("SELECT mapid, difficulty, level_min, level_max, item, item2, quest_done_A, quest_done_H, completed_achievement, quest_failed_text FROM access_requirement"); if (!result) { @@ -6156,17 +6221,15 @@ void ObjectMgr::LoadAccessRequirements() uint8 difficulty = fields[1].GetUInt8(); uint32 requirement_ID = MAKE_PAIR32(mapid, difficulty); - AccessRequirement* ar = new AccessRequirement(); - - ar->levelMin = fields[2].GetUInt8(); - ar->levelMax = fields[3].GetUInt8(); - ar->item_level = fields[4].GetUInt16(); - ar->item = fields[5].GetUInt32(); - ar->item2 = fields[6].GetUInt32(); - ar->quest_A = fields[7].GetUInt32(); - ar->quest_H = fields[8].GetUInt32(); - ar->achievement = fields[9].GetUInt32(); - ar->questFailedText = fields[10].GetString(); + AccessRequirement* ar = new AccessRequirement(); + ar->levelMin = fields[2].GetUInt8(); + ar->levelMax = fields[3].GetUInt8(); + ar->item = fields[4].GetUInt32(); + ar->item2 = fields[5].GetUInt32(); + ar->quest_A = fields[6].GetUInt32(); + ar->quest_H = fields[7].GetUInt32(); + ar->achievement = fields[8].GetUInt32(); + ar->questFailedText = fields[9].GetString(); if (ar->item) { @@ -6224,7 +6287,7 @@ void ObjectMgr::LoadAccessRequirements() /* * Searches for the areatrigger which teleports players out of the given map with instance_template.parent field support */ -AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const +AreaTriggerStruct const* ObjectMgr::GetGoBackTrigger(uint32 Map) const { bool useParentDbValue = false; uint32 parentId = 0; @@ -6257,7 +6320,7 @@ AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const /** * Searches for the areatrigger which teleports players to the given map */ -AreaTrigger const* ObjectMgr::GetMapEntranceTrigger(uint32 Map) const +AreaTriggerStruct const* ObjectMgr::GetMapEntranceTrigger(uint32 Map) const { for (AreaTriggerContainer::const_iterator itr = _areaTriggerStore.begin(); itr != _areaTriggerStore.end(); ++itr) { @@ -6326,6 +6389,10 @@ void ObjectMgr::SetHighestGuids() result = CharacterDatabase.Query("SELECT MAX(guid) FROM groups"); if (result) sGroupMgr->SetGroupDbStoreSize((*result)[0].GetUInt32()+1); + + result = CharacterDatabase.Query("SELECT MAX(itemId) from character_void_storage"); + if (result) + _voidItemId = (*result)[0].GetUInt64()+1; } uint32 ObjectMgr::GenerateAuctionID() @@ -6397,6 +6464,11 @@ uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh) ASSERT(_hiCorpseGuid < 0xFFFFFFFE && "Corpse guid overflow!"); return _hiCorpseGuid++; } + case HIGHGUID_AREATRIGGER: + { + ASSERT(_hiAreaTriggerGuid < 0xFFFFFFFE && "AreaTrigger guid overflow!"); + return _hiAreaTriggerGuid++; + } case HIGHGUID_DYNAMICOBJECT: { ASSERT(_hiDoGuid < 0xFFFFFFFE && "DynamicObject guid overflow!"); @@ -6473,7 +6545,7 @@ inline void CheckGOSpellId(GameObjectTemplate const* goInfo, uint32 dataN, uint3 goInfo->entry, goInfo->type, N, dataN, dataN); } -inline void CheckAndFixGOChairHeightId(GameObjectTemplate const* goInfo, uint32 const& dataN, uint32 N) +inline void CheckAndFixGOChairHeightId(GameObjectTemplate const* goInfo, uint32& dataN, uint32 N) { if (dataN <= (UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR)) return; @@ -6482,7 +6554,7 @@ inline void CheckAndFixGOChairHeightId(GameObjectTemplate const* goInfo, uint32 goInfo->entry, goInfo->type, N, dataN, UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR); // prevent client and server unexpected work - const_cast<uint32&>(dataN) = 0; + dataN = 0; } inline void CheckGONoDamageImmuneId(GameObjectTemplate* goTemplate, uint32 dataN, uint32 N) @@ -6512,8 +6584,10 @@ void ObjectMgr::LoadGameObjectTemplate() QueryResult result = WorldDatabase.Query("SELECT entry, type, displayId, name, IconName, castBarCaption, unk1, faction, flags, size, questItem1, questItem2, questItem3, " // 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 "questItem4, questItem5, questItem6, data0, data1, data2, data3, data4, data5, data6, data7, data8, data9, data10, data11, data12, " - // 29 30 31 32 33 34 35 36 37 38 39 40 41 - "data13, data14, data15, data16, data17, data18, data19, data20, data21, data22, data23, AIName, ScriptName " + // 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 + "data13, data14, data15, data16, data17, data18, data19, data20, data21, data22, data23, data24, data25, data26, data27, data28, " + // 45 46 47 48 49 50 + "data29, data30, data31, unkInt32, AIName, ScriptName " "FROM gameobject_template"); if (!result) @@ -6547,10 +6621,11 @@ void ObjectMgr::LoadGameObjectTemplate() got.questItems[i] = fields[10 + i].GetUInt32(); for (uint8 i = 0; i < MAX_GAMEOBJECT_DATA; ++i) - got.raw.data[i] = fields[16 + i].GetInt32(); // data1 and data6 can be -1 + got.raw.data[i] = fields[16 + i].GetUInt32(); - got.AIName = fields[40].GetString(); - got.ScriptId = GetScriptId(fields[41].GetCString()); + got.unkInt32 = fields[48].GetInt32(); + got.AIName = fields[49].GetString(); + got.ScriptId = GetScriptId(fields[50].GetCString()); // Checks @@ -6787,7 +6862,7 @@ std::string ObjectMgr::GeneratePetName(uint32 entry) if (!cinfo) return std::string(); - char* petname = GetPetName(cinfo->family, sWorld->GetDefaultDbcLocale()); + char const* petname = GetPetName(cinfo->family, sWorld->GetDefaultDbcLocale()); if (petname) return std::string(petname); else @@ -6802,8 +6877,16 @@ uint32 ObjectMgr::GeneratePetNumber() return ++_hiPetNumber; } +uint64 ObjectMgr::GenerateVoidStorageItemId() +{ + return ++_voidItemId; +} + void ObjectMgr::LoadCorpses() { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0 + uint32 oldMSTime = getMSTime(); PreparedQueryResult result = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSES)); @@ -6818,7 +6901,7 @@ void ObjectMgr::LoadCorpses() { Field* fields = result->Fetch(); uint32 guid = fields[16].GetUInt32(); - CorpseType type = CorpseType(fields[13].GetUInt8()); + CorpseType type = CorpseType(fields[12].GetUInt8()); if (type >= MAX_CORPSE_TYPE) { TC_LOG_ERROR("misc", "Corpse (guid: %u) have wrong corpse type (%u), not loading.", guid, type); @@ -7006,8 +7089,8 @@ void ObjectMgr::LoadReputationSpilloverTemplate() _repSpilloverTemplateStore.clear(); // for reload case - uint32 count = 0; // 0 1 2 3 4 5 6 7 8 9 10 11 12 - QueryResult result = WorldDatabase.Query("SELECT faction, faction1, rate_1, rank_1, faction2, rate_2, rank_2, faction3, rate_3, rank_3, faction4, rate_4, rank_4 FROM reputation_spillover_template"); + uint32 count = 0; // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + QueryResult result = WorldDatabase.Query("SELECT faction, faction1, rate_1, rank_1, faction2, rate_2, rank_2, faction3, rate_3, rank_3, faction4, rate_4, rank_4, faction5, rate_5, rank_5 FROM reputation_spillover_template"); if (!result) { @@ -7035,6 +7118,9 @@ void ObjectMgr::LoadReputationSpilloverTemplate() repTemplate.faction[3] = fields[10].GetUInt16(); repTemplate.faction_rate[3] = fields[11].GetFloat(); repTemplate.faction_rank[3] = fields[12].GetUInt8(); + repTemplate.faction[4] = fields[13].GetUInt16(); + repTemplate.faction_rate[4] = fields[14].GetFloat(); + repTemplate.faction_rank[4] = fields[15].GetUInt8(); FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId); @@ -7100,6 +7186,12 @@ void ObjectMgr::LoadReputationSpilloverTemplate() TC_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[3]); continue; } + FactionEntry const* factionEntry4 = sFactionStore.LookupEntry(repTemplate.faction[4]); + if (repTemplate.faction[4] && !factionEntry4) + { + TC_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[4]); + continue; + } _repSpilloverTemplateStore[factionId] = repTemplate; @@ -8213,7 +8305,7 @@ void ObjectMgr::LoadTrainerSpell() if (!result) { - TC_LOG_ERROR("sql.sql", ">> Loaded 0 Trainers. DB table `npc_trainer` is empty!"); + TC_LOG_ERROR("server.loading", ">> Loaded 0 Trainers. DB table `npc_trainer` is empty!"); return; } @@ -8240,11 +8332,12 @@ void ObjectMgr::LoadTrainerSpell() TC_LOG_INFO("server.loading", ">> Loaded %d Trainers in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, std::set<uint32> *skip_vendors) +int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, uint8 type, std::set<uint32> *skip_vendors) { // find all items from the reference vendor PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_NPC_VENDOR_REF); stmt->setUInt32(0, uint32(item)); + stmt->setUInt8(1, type); PreparedQueryResult result = WorldDatabase.Query(stmt); if (!result) @@ -8259,19 +8352,20 @@ int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, std::set<uint32> *s // if item is a negative, its a reference if (item_id < 0) - count += LoadReferenceVendor(vendor, -item_id, skip_vendors); + count += LoadReferenceVendor(vendor, -item_id, type, skip_vendors); else { - int32 maxcount = fields[1].GetUInt8(); + int32 maxcount = fields[1].GetUInt32(); uint32 incrtime = fields[2].GetUInt32(); uint32 ExtendedCost = fields[3].GetUInt32(); + uint8 type = fields[4].GetUInt8(); - if (!IsVendorItemValid(vendor, item_id, maxcount, incrtime, ExtendedCost, NULL, skip_vendors)) + if (!IsVendorItemValid(vendor, item_id, maxcount, incrtime, ExtendedCost, type, NULL, skip_vendors)) continue; VendorItemData& vList = _cacheVendorItemStore[vendor]; - vList.AddItem(item_id, maxcount, incrtime, ExtendedCost); + vList.AddItem(item_id, maxcount, incrtime, ExtendedCost, type); ++count; } } while (result->NextRow()); @@ -8290,11 +8384,11 @@ void ObjectMgr::LoadVendors() std::set<uint32> skip_vendors; - QueryResult result = WorldDatabase.Query("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor ORDER BY entry, slot ASC"); + QueryResult result = WorldDatabase.Query("SELECT entry, item, maxcount, incrtime, ExtendedCost, type FROM npc_vendor ORDER BY entry, slot ASC"); if (!result) { - TC_LOG_ERROR("sql.sql", ">> Loaded 0 Vendors. DB table `npc_vendor` is empty!"); + TC_LOG_ERROR("server.loading", ">> Loaded 0 Vendors. DB table `npc_vendor` is empty!"); return; } @@ -8309,19 +8403,20 @@ void ObjectMgr::LoadVendors() // if item is a negative, its a reference if (item_id < 0) - count += LoadReferenceVendor(entry, -item_id, &skip_vendors); + count += LoadReferenceVendor(entry, -item_id, 0, &skip_vendors); else { - uint32 maxcount = fields[2].GetUInt8(); + uint32 maxcount = fields[2].GetUInt32(); uint32 incrtime = fields[3].GetUInt32(); uint32 ExtendedCost = fields[4].GetUInt32(); + uint8 type = fields[5].GetUInt8(); - if (!IsVendorItemValid(entry, item_id, maxcount, incrtime, ExtendedCost, NULL, &skip_vendors)) + if (!IsVendorItemValid(entry, item_id, maxcount, incrtime, ExtendedCost, type, NULL, &skip_vendors)) continue; VendorItemData& vList = _cacheVendorItemStore[entry]; - vList.AddItem(item_id, maxcount, incrtime, ExtendedCost); + vList.AddItem(item_id, maxcount, incrtime, ExtendedCost, type); ++count; } } @@ -8450,10 +8545,10 @@ void ObjectMgr::LoadGossipMenuItems() TC_LOG_INFO("server.loading", ">> Loaded %u gossip_menu_option entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, bool persist /*= true*/) +void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, uint8 type, bool persist /*= true*/) { VendorItemData& vList = _cacheVendorItemStore[entry]; - vList.AddItem(item, maxcount, incrtime, extendedCost); + vList.AddItem(item, maxcount, incrtime, extendedCost, type); if (persist) { @@ -8464,18 +8559,19 @@ void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 stmt->setUInt8(2, maxcount); stmt->setUInt32(3, incrtime); stmt->setUInt32(4, extendedCost); + stmt->setUInt8(5, type); WorldDatabase.Execute(stmt); } } -bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, bool persist /*= true*/) +bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, uint8 type, bool persist /*= true*/) { CacheVendorItemContainer::iterator iter = _cacheVendorItemStore.find(entry); if (iter == _cacheVendorItemStore.end()) return false; - if (!iter->second.RemoveItem(item)) + if (!iter->second.RemoveItem(item, type)) return false; if (persist) @@ -8484,6 +8580,7 @@ bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, bool persist /*= tru stmt->setUInt32(0, entry); stmt->setUInt32(1, item); + stmt->setUInt8(2, type); WorldDatabase.Execute(stmt); } @@ -8491,7 +8588,7 @@ bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, bool persist /*= tru return true; } -bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* player, std::set<uint32>* skip_vendors, uint32 ORnpcflag) const +bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 id, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, uint8 type, Player* player, std::set<uint32>* skip_vendors, uint32 ORnpcflag) const { CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(vendor_entry); if (!cInfo) @@ -8518,12 +8615,13 @@ bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 max return false; } - if (!sObjectMgr->GetItemTemplate(item_id)) + if ((type == ITEM_VENDOR_TYPE_ITEM && !sObjectMgr->GetItemTemplate(id)) || + (type == ITEM_VENDOR_TYPE_CURRENCY && !sCurrencyTypesStore.LookupEntry(id))) { if (player) - ChatHandler(player->GetSession()).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id); + ChatHandler(player->GetSession()).PSendSysMessage(LANG_ITEM_NOT_FOUND, id, type); else - TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore", vendor_entry, item_id); + TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u, type %u), ignore", vendor_entry, id, type); return false; } @@ -8532,37 +8630,46 @@ bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 max if (player) ChatHandler(player->GetSession()).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST, ExtendedCost); else - TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore", item_id, ExtendedCost, vendor_entry); + TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore", id, ExtendedCost, vendor_entry); return false; } - if (maxcount > 0 && incrtime == 0) + if (type == ITEM_VENDOR_TYPE_ITEM) // not applicable to currencies { - if (player) - ChatHandler(player->GetSession()).PSendSysMessage("MaxCount != 0 (%u) but IncrTime == 0", maxcount); - else - TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` has `maxcount` (%u) for item %u of vendor (Entry: %u) but `incrtime`=0, ignore", maxcount, item_id, vendor_entry); - return false; - } - else if (maxcount == 0 && incrtime > 0) - { - if (player) - ChatHandler(player->GetSession()).PSendSysMessage("MaxCount == 0 but IncrTime<>= 0"); - else - TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` has `maxcount`=0 for item %u of vendor (Entry: %u) but `incrtime`<>0, ignore", item_id, vendor_entry); - return false; + if (maxcount > 0 && incrtime == 0) + { + if (player) + ChatHandler(player->GetSession()).PSendSysMessage("MaxCount != 0 (%u) but IncrTime == 0", maxcount); + else + TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` has `maxcount` (%u) for item %u of vendor (Entry: %u) but `incrtime`=0, ignore", maxcount, id, vendor_entry); + return false; + } + else if (maxcount == 0 && incrtime > 0) + { + if (player) + ChatHandler(player->GetSession()).PSendSysMessage("MaxCount == 0 but IncrTime<>= 0"); + else + TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` has `maxcount`=0 for item %u of vendor (Entry: %u) but `incrtime`<>0, ignore", id, vendor_entry); + return false; + } } VendorItemData const* vItems = GetNpcVendorItemList(vendor_entry); if (!vItems) return true; // later checks for non-empty lists - if (vItems->FindItemCostPair(item_id, ExtendedCost)) + if (vItems->FindItemCostPair(id, ExtendedCost, type)) { if (player) - ChatHandler(player->GetSession()).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, ExtendedCost); + ChatHandler(player->GetSession()).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, id, ExtendedCost, type); else - TC_LOG_ERROR("sql.sql", "Table `npc_vendor` has duplicate items %u (with extended cost %u) for vendor (Entry: %u), ignoring", item_id, ExtendedCost, vendor_entry); + TC_LOG_ERROR("sql.sql", "Table `npc_vendor` has duplicate items %u (with extended cost %u, type %u) for vendor (Entry: %u), ignoring", id, ExtendedCost, type, vendor_entry); + return false; + } + + if (type == ITEM_VENDOR_TYPE_CURRENCY && maxcount == 0) + { + TC_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` have Item (Entry: %u, type: %u) with missing maxcount for vendor (%u), ignore", id, type, vendor_entry); return false; } @@ -8583,7 +8690,7 @@ void ObjectMgr::LoadScriptNames() "UNION " "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " "UNION " - "SELECT DISTINCT(ScriptName) FROM item_template WHERE ScriptName <> '' " + "SELECT DISTINCT(ScriptName) FROM item_script_names WHERE ScriptName <> '' " "UNION " "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' " "UNION " @@ -8840,8 +8947,8 @@ CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unit void ObjectMgr::LoadCreatureClassLevelStats() { uint32 oldMSTime = getMSTime(); - - QueryResult result = WorldDatabase.Query("SELECT level, class, basehp0, basehp1, basehp2, basemana, basearmor, attackpower, rangedattackpower, damage_base, damage_exp1, damage_exp2 FROM creature_classlevelstats"); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + QueryResult result = WorldDatabase.Query("SELECT level, class, basehp0, basehp1, basehp2, basehp3, basemana, basearmor, attackpower, rangedattackpower, damage_base, damage_exp1, damage_exp2, damage_exp3 FROM creature_classlevelstats"); if (!result) { @@ -8864,7 +8971,7 @@ void ObjectMgr::LoadCreatureClassLevelStats() for (uint8 i = 0; i < MAX_EXPANSIONS; ++i) { - stats.BaseHealth[i] = fields[2 + i].GetUInt16(); + stats.BaseHealth[i] = fields[2 + i].GetUInt32(); if (stats.BaseHealth[i] == 0) { @@ -8872,7 +8979,7 @@ void ObjectMgr::LoadCreatureClassLevelStats() stats.BaseHealth[i] = 1; } - stats.BaseDamage[i] = fields[9 + i].GetFloat(); + stats.BaseDamage[i] = fields[10 + i].GetFloat(); if (stats.BaseDamage[i] < 0.0f) { TC_LOG_ERROR("sql.sql", "Creature base stats for class %u, level %u has invalid negative base damage[%u] - set to 0.0", Class, Level, i); @@ -8880,11 +8987,11 @@ void ObjectMgr::LoadCreatureClassLevelStats() } } - stats.BaseMana = fields[5].GetUInt16(); - stats.BaseArmor = fields[6].GetUInt16(); + stats.BaseMana = fields[6].GetUInt16(); + stats.BaseArmor = fields[7].GetUInt16(); - stats.AttackPower = fields[7].GetUInt16(); - stats.RangedAttackPower = fields[8].GetUInt16(); + stats.AttackPower = fields[8].GetUInt16(); + stats.RangedAttackPower = fields[9].GetUInt16(); _creatureBaseStatsStore[MAKE_PAIR16(Level, Class)] = stats; @@ -9045,6 +9152,74 @@ void ObjectMgr::LoadFactionChangeReputations() TC_LOG_INFO("server.loading", ">> Loaded %u faction change reputation pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadHotfixData() +{ + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.Query("SELECT entry, type, UNIX_TIMESTAMP(hotfixDate) FROM hotfix_data"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 hotfix info entries. DB table `hotfix_data` is empty."); + return; + } + + uint32 count = 0; + + _hotfixData.reserve(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + HotfixInfo info; + info.Entry = fields[0].GetUInt32(); + info.Type = fields[1].GetUInt32(); + info.Timestamp = fields[2].GetUInt64(); + _hotfixData.push_back(info); + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u hotfix info entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void ObjectMgr::LoadMissingKeyChains() +{ + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.Query("SELECT keyId, k1, k2, k3, k4, k5, k6, k7, k8, " + "k9, k10, k11, k12, k13, k14, k15, k16, " + "k17, k18, k19, k20, k21, k22, k23, k24, " + "k25, k26, k27, k28, k29, k30, k31, k32 " + "FROM keychain_db2 ORDER BY keyId DESC"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 KeyChain entries. DB table `keychain_db2` is empty."); + return; + } + + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + + KeyChainEntry* kce = sKeyChainStore.CreateEntry(id, true); + kce->Id = id; + for (uint32 i = 0; i < KEYCHAIN_SIZE; ++i) + kce->Key[i] = fields[1 + i].GetUInt8(); + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u KeyChain entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + void ObjectMgr::LoadFactionChangeSpells() { uint32 oldMSTime = getMSTime(); @@ -9115,6 +9290,89 @@ void ObjectMgr::LoadFactionChangeTitles() TC_LOG_INFO("server.loading", ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadPhaseDefinitions() +{ + _PhaseDefinitionStore.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 2 3 + QueryResult result = WorldDatabase.Query("SELECT zoneId, entry, phaseId, phaseGroup FROM `phase_definitions` ORDER BY `entry` ASC"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 phasing definitions. DB table `phase_definitions` is empty."); + return; + } + + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + + PhaseDefinition PhaseDefinition; + + PhaseDefinition.zoneId = fields[0].GetUInt32(); + PhaseDefinition.entry = fields[1].GetUInt32(); + PhaseDefinition.phaseId = fields[2].GetUInt32(); + PhaseDefinition.phaseGroup = fields[3].GetUInt32(); + + if (PhaseDefinition.phaseGroup && PhaseDefinition.phaseId) + { + TC_LOG_ERROR("sql.sql", "Phase definition for zone %u (Entry: %u) has phaseGroup and phaseId set, phaseGroup set to 0", PhaseDefinition.zoneId, PhaseDefinition.entry); + PhaseDefinition.phaseGroup = 0; + } + _PhaseDefinitionStore[PhaseDefinition.zoneId].push_back(PhaseDefinition); + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u phasing definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void ObjectMgr::LoadPhaseInfo() +{ + _PhaseInfoStore.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 2 + QueryResult result = WorldDatabase.Query("SELECT id, worldmapareaswap, terrainswapmap FROM `phase_info`"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 phase infos. DB table `phase_info` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + PhaseInfo phaseInfo; + phaseInfo.phaseId = fields[0].GetUInt32(); + + PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseInfo.phaseId); + if (!phase) + { + TC_LOG_ERROR("sql.sql", "Phase %u defined in `phase_info` does not exists, skipped.", phaseInfo.phaseId); + continue; + } + + phaseInfo.worldMapAreaSwap = fields[1].GetUInt32(); + phaseInfo.terrainSwapMap = fields[2].GetUInt32(); + + _PhaseInfoStore[phaseInfo.phaseId] = phaseInfo; + + ++count; + } + while (result->NextRow()); + TC_LOG_INFO("server.loading", ">> Loaded %u phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) { GameObjectTemplateContainer::const_iterator itr = _gameObjectTemplateStore.find(entry); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 738b99778f8..45671f016c8 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -41,11 +41,10 @@ #include <limits> #include "ConditionMgr.h" #include <functional> +#include "DB2Stores.h" class Item; struct AccessRequirement; -struct PlayerClassInfo; -struct PlayerClassLevelInfo; struct PlayerInfo; struct PlayerLevelInfo; @@ -130,6 +129,34 @@ typedef std::map<uint32, PageText> PageTextContainer; // Benchmarked: Faster than std::map (insert/find) typedef std::unordered_map<uint16, InstanceTemplate> InstanceTemplateContainer; +// Phasing (visibility) +enum PhasingFlags +{ + PHASE_FLAG_OVERWRITE_EXISTING = 0x01, // don't stack with existing phases, overwrites existing phases + PHASE_FLAG_NO_MORE_PHASES = 0x02, // stop calculating phases after this phase was applied (no more phases will be applied) + PHASE_FLAG_NEGATE_PHASE = 0x04 // negate instead to add the phasemask +}; + +struct PhaseInfo +{ + uint32 phaseId; + uint32 worldMapAreaSwap; + uint32 terrainSwapMap; +}; + +typedef std::unordered_map<uint32, PhaseInfo> PhaseInfoContainer; + +struct PhaseDefinition +{ + uint32 zoneId; + uint32 entry; + uint32 phaseId; + uint32 phaseGroup; +}; + +typedef std::list<PhaseDefinition> PhaseDefinitionContainer; +typedef std::unordered_map<uint32 /*zoneId*/, PhaseDefinitionContainer> PhaseDefinitionStore; + struct GameTele { float position_x; @@ -400,7 +427,7 @@ struct SpellClickInfo typedef std::multimap<uint32, SpellClickInfo> SpellClickInfoContainer; typedef std::pair<SpellClickInfoContainer::const_iterator, SpellClickInfoContainer::const_iterator> SpellClickInfoMapBounds; -struct AreaTrigger +struct AreaTriggerStruct { uint32 target_mapId; float target_X; @@ -484,7 +511,6 @@ typedef std::map<TempSummonGroupKey, std::vector<TempSummonData> > TempSummonDat typedef std::unordered_map<uint32, CreatureLocale> CreatureLocaleContainer; typedef std::unordered_map<uint32, GameObjectLocale> GameObjectLocaleContainer; typedef std::unordered_map<uint32, ItemLocale> ItemLocaleContainer; -typedef std::unordered_map<uint32, ItemSetNameLocale> ItemSetNameLocaleContainer; typedef std::unordered_map<uint32, QuestLocale> QuestLocaleContainer; typedef std::unordered_map<uint32, NpcTextLocale> NpcTextLocaleContainer; typedef std::unordered_map<uint32, PageTextLocale> PageTextLocaleContainer; @@ -627,6 +653,7 @@ struct GraveYardData }; typedef std::multimap<uint32, GraveYardData> GraveYardContainer; +typedef std::unordered_map<uint32 /* graveyard Id */, float /* orientation */> GraveyardOrientationContainer; typedef std::pair<GraveYardContainer::const_iterator, GraveYardContainer::const_iterator> GraveYardMapBounds; typedef std::pair<GraveYardContainer::iterator, GraveYardContainer::iterator> GraveYardMapBoundsNonConst; @@ -681,6 +708,15 @@ struct DungeonEncounter typedef std::list<DungeonEncounter const*> DungeonEncounterList; typedef std::unordered_map<uint32, DungeonEncounterList> DungeonEncounterContainer; +struct HotfixInfo +{ + uint32 Type; + uint32 Timestamp; + uint32 Entry; +}; + +typedef std::vector<HotfixInfo> HotfixData; + class PlayerDumpReader; class ObjectMgr @@ -702,7 +738,7 @@ class ObjectMgr typedef std::unordered_map<uint32, Quest*> QuestMap; - typedef std::unordered_map<uint32, AreaTrigger> AreaTriggerContainer; + typedef std::unordered_map<uint32, AreaTriggerStruct> AreaTriggerContainer; typedef std::unordered_map<uint32, uint32> AreaTriggerScriptContainer; @@ -722,7 +758,7 @@ class ObjectMgr GameObjectTemplate const* GetGameObjectTemplate(uint32 entry); GameObjectTemplateContainer const* GetGameObjectTemplates() const { return &_gameObjectTemplateStore; } - int LoadReferenceVendor(int32 vendor, int32 item_id, std::set<uint32> *skip_vendors); + int LoadReferenceVendor(int32 vendor, int32 item, uint8 type, std::set<uint32> *skip_vendors); void LoadGameObjectTemplate(); void AddGameobjectInfo(GameObjectTemplate* goinfo); @@ -739,25 +775,11 @@ class ObjectMgr ItemTemplate const* GetItemTemplate(uint32 entry); ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; } - ItemSetNameEntry const* GetItemSetNameEntry(uint32 itemId) - { - ItemSetNameContainer::iterator itr = _itemSetNameStore.find(itemId); - if (itr != _itemSetNameStore.end()) - return &itr->second; - return NULL; - } - InstanceTemplate const* GetInstanceTemplate(uint32 mapId); PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint8 level) const; - PlayerClassInfo const* GetPlayerClassInfo(uint32 class_) const - { - if (class_ >= MAX_CLASSES) - return NULL; - return _playerClassInfo[class_]; - } - void GetPlayerClassLevelInfo(uint32 class_, uint8 level, PlayerClassLevelInfo* info) const; + void GetPlayerClassLevelInfo(uint32 class_, uint8 level, uint32& baseHP, uint32& baseMana) const; PlayerInfo const* GetPlayerInfo(uint32 race, uint32 class_) const; @@ -822,7 +844,7 @@ class ObjectMgr void LoadGraveyardZones(); GraveYardData const* FindGraveYardData(uint32 id, uint32 zone); - AreaTrigger const* GetAreaTrigger(uint32 trigger) const + AreaTriggerStruct const* GetAreaTrigger(uint32 trigger) const { AreaTriggerContainer::const_iterator itr = _areaTriggerStore.find(trigger); if (itr != _areaTriggerStore.end()) @@ -838,8 +860,8 @@ class ObjectMgr return NULL; } - AreaTrigger const* GetGoBackTrigger(uint32 Map) const; - AreaTrigger const* GetMapEntranceTrigger(uint32 Map) const; + AreaTriggerStruct const* GetGoBackTrigger(uint32 Map) const; + AreaTriggerStruct const* GetMapEntranceTrigger(uint32 Map) const; uint32 GetAreaTriggerScriptId(uint32 trigger_id); SpellScriptsBounds GetSpellScriptsBounds(uint32 spellId); @@ -959,6 +981,7 @@ class ObjectMgr void LoadDbScriptStrings(); void LoadCreatureClassLevelStats(); void LoadCreatureLocales(); + void LoadGraveyardOrientations(); void LoadCreatureTemplates(); void LoadCreatureTemplateAddons(); void CheckCreatureTemplate(CreatureTemplate const* cInfo); @@ -972,9 +995,9 @@ class ObjectMgr void LoadGameObjectLocales(); void LoadGameobjects(); void LoadItemTemplates(); + void LoadItemTemplateAddon(); + void LoadItemScriptNames(); void LoadItemLocales(); - void LoadItemSetNames(); - void LoadItemSetNameLocales(); void LoadQuestLocales(); void LoadNpcTextLocales(); void LoadPageTextLocales(); @@ -1024,6 +1047,9 @@ class ObjectMgr void LoadTrainerSpell(); void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel); + void LoadPhaseDefinitions(); + void LoadPhaseInfo(); + std::string GeneratePetName(uint32 entry); uint32 GetBaseXP(uint8 level); uint32 GetXPForLevel(uint8 level) const; @@ -1044,6 +1070,7 @@ class ObjectMgr uint64 GenerateEquipmentSetGuid(); uint32 GenerateMailID(); uint32 GeneratePetNumber(); + uint64 GenerateVoidStorageItemId(); typedef std::multimap<int32, uint32> ExclusiveQuestGroups; typedef std::pair<ExclusiveQuestGroups::const_iterator, ExclusiveQuestGroups::const_iterator> ExclusiveQuestGroupsBounds; @@ -1131,12 +1158,6 @@ class ObjectMgr if (itr == _itemLocaleStore.end()) return NULL; return &itr->second; } - ItemSetNameLocale const* GetItemSetNameLocale(uint32 entry) const - { - ItemSetNameLocaleContainer::const_iterator itr = _itemSetNameLocaleStore.find(entry); - if (itr == _itemSetNameLocaleStore.end())return NULL; - return &itr->second; - } QuestLocale const* GetQuestLocale(uint32 entry) const { QuestLocaleContainer::const_iterator itr = _questLocaleStore.find(entry); @@ -1240,9 +1261,19 @@ class ObjectMgr return &iter->second; } - void AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, bool persist = true); // for event - bool RemoveVendorItem(uint32 entry, uint32 item, bool persist = true); // for event - bool IsVendorItemValid(uint32 vendor_entry, uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* player = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0) const; + + float const* GetGraveyardOrientation(uint32 id) const + { + GraveyardOrientationContainer::const_iterator iter = _graveyardOrientations.find(id); + if (iter != _graveyardOrientations.end()) + return &iter->second; + + return NULL; + } + + void AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, uint8 type, bool persist = true); // for event + bool RemoveVendorItem(uint32 entry, uint32 item, uint8 type, bool persist = true); // for event + bool IsVendorItemValid(uint32 vendor_entry, uint32 id, int32 maxcount, uint32 ptime, uint32 ExtendedCost, uint8 type, Player* player = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0) const; void LoadScriptNames(); ScriptNameContainer &GetScriptNames() { return _scriptNamesStore; } @@ -1273,6 +1304,8 @@ class ObjectMgr return _gossipMenuItemsStore.equal_range(uiMenuId); } + PhaseInfo const* GetPhaseInfo(uint32 phase) { return _PhaseInfoStore.find(phase) != _PhaseInfoStore.end() ? &_PhaseInfoStore[phase] : nullptr; } + // for wintergrasp only GraveYardContainer GraveYardStore; @@ -1299,6 +1332,21 @@ class ObjectMgr bool IsTransportMap(uint32 mapId) const { return _transportMaps.count(mapId) != 0; } + void LoadHotfixData(); + HotfixData const& GetHotfixData() const { return _hotfixData; } + time_t GetHotfixDate(uint32 entry, uint32 type) const + { + time_t ret = 0; + for (HotfixData::const_iterator itr = _hotfixData.begin(); itr != _hotfixData.end(); ++itr) + if (itr->Entry == entry && itr->Type == type) + if (time_t(itr->Timestamp) > ret) + ret = time_t(itr->Timestamp); + + return ret ? ret : time(NULL); + } + + void LoadMissingKeyChains(); + private: // first free id for selected id type uint32 _auctionId; @@ -1306,6 +1354,7 @@ class ObjectMgr uint32 _itemTextId; uint32 _mailId; uint32 _hiPetNumber; + uint64 _voidItemId; // first free low guid for selected guid type uint32 _hiCharGuid; @@ -1316,6 +1365,7 @@ class ObjectMgr uint32 _hiGoGuid; uint32 _hiDoGuid; uint32 _hiCorpseGuid; + uint32 _hiAreaTriggerGuid; uint32 _hiMoTransGuid; QuestMap _questTemplates; @@ -1369,6 +1419,9 @@ class ObjectMgr PageTextContainer _pageTextStore; InstanceTemplateContainer _instanceTemplateStore; + PhaseDefinitionStore _PhaseDefinitionStore; + PhaseInfoContainer _PhaseInfoStore; + private: void LoadScripts(ScriptsType type); void CheckScripts(ScriptsType type, std::set<int32>& ids); @@ -1383,8 +1436,6 @@ class ObjectMgr // PetLevelInfoContainer[creature_id][level] PetLevelInfoContainer _petInfoStore; // [creature_id][level] - PlayerClassInfo* _playerClassInfo[MAX_CLASSES]; - void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const; PlayerInfo* _playerInfo[MAX_RACES][MAX_CLASSES]; @@ -1402,9 +1453,6 @@ class ObjectMgr HalfNameContainer _petHalfName0; HalfNameContainer _petHalfName1; - typedef std::unordered_map<uint32, ItemSetNameEntry> ItemSetNameContainer; - ItemSetNameContainer _itemSetNameStore; - MapObjectGuids _mapObjectGuidsStore; CreatureDataContainer _creatureDataStore; CreatureTemplateContainer _creatureTemplateStore; @@ -1423,7 +1471,6 @@ class ObjectMgr BroadcastTextContainer _broadcastTextStore; ItemTemplateContainer _itemTemplateStore; ItemLocaleContainer _itemLocaleStore; - ItemSetNameLocaleContainer _itemSetNameLocaleStore; QuestLocaleContainer _questLocaleStore; NpcTextLocaleContainer _npcTextLocaleStore; PageTextLocaleContainer _pageTextLocaleStore; @@ -1434,6 +1481,8 @@ class ObjectMgr CacheVendorItemContainer _cacheVendorItemStore; CacheTrainerSpellContainer _cacheTrainerSpellStore; + GraveyardOrientationContainer _graveyardOrientations; + std::set<uint32> _difficultyEntries[MAX_DIFFICULTY - 1]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate std::set<uint32> _hasDifficultyEntries[MAX_DIFFICULTY - 1]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate @@ -1445,6 +1494,7 @@ class ObjectMgr GO_TO_CREATURE // GO is dependant on creature }; + HotfixData _hotfixData; std::set<uint32> _transportMaps; // Helper container storing map ids that are for transports only, loaded from gameobject_template }; diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index 013d0ef5794..9ed8549e9a1 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -30,6 +30,7 @@ class DynamicObject; class GameObject; class Pet; class Player; +class AreaTrigger; #define MAX_NUMBER_OF_CELLS 8 @@ -57,13 +58,14 @@ class Player; // Creature used instead pet to simplify *::Visit templates (not required duplicate code for Creature->Pet case) typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, DynamicObject/*farsight target*/) AllWorldObjectTypes; -typedef TYPELIST_4(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/) AllGridObjectTypes; +typedef TYPELIST_5(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/, AreaTrigger) AllGridObjectTypes; typedef GridRefManager<Corpse> CorpseMapType; typedef GridRefManager<Creature> CreatureMapType; typedef GridRefManager<DynamicObject> DynamicObjectMapType; typedef GridRefManager<GameObject> GameObjectMapType; typedef GridRefManager<Player> PlayerMapType; +typedef GridRefManager<AreaTrigger> AreaTriggerMapType; enum GridMapTypeMask { @@ -72,7 +74,8 @@ enum GridMapTypeMask GRID_MAP_TYPE_MASK_DYNAMICOBJECT = 0x04, GRID_MAP_TYPE_MASK_GAMEOBJECT = 0x08, GRID_MAP_TYPE_MASK_PLAYER = 0x10, - GRID_MAP_TYPE_MASK_ALL = 0x1F + GRID_MAP_TYPE_MASK_AREATRIGGER = 0x20, + GRID_MAP_TYPE_MASK_ALL = 0x3F }; typedef Grid<Player, AllWorldObjectTypes, AllGridObjectTypes> GridType; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 270d598d53a..8040728133f 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -263,7 +263,7 @@ void MessageDistDeliverer::Visit(PlayerMapType &m) for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { Player* target = iter->GetSource(); - if (!target->InSamePhase(i_phaseMask)) + if (!target->IsInPhase(i_source)) continue; if (target->GetExactDist2dSq(i_source) > i_distSq) @@ -288,7 +288,7 @@ void MessageDistDeliverer::Visit(CreatureMapType &m) for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { Creature* target = iter->GetSource(); - if (!target->InSamePhase(i_phaseMask)) + if (!target->IsInPhase(i_source)) continue; if (target->GetExactDist2dSq(i_source) > i_distSq) @@ -310,7 +310,7 @@ void MessageDistDeliverer::Visit(DynamicObjectMapType &m) for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { DynamicObject* target = iter->GetSource(); - if (!target->InSamePhase(i_phaseMask)) + if (!target->IsInPhase(i_source)) continue; if (target->GetExactDist2dSq(i_source) > i_distSq) @@ -378,3 +378,5 @@ bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u) template void ObjectUpdater::Visit<Creature>(CreatureMapType&); template void ObjectUpdater::Visit<GameObject>(GameObjectMapType&); template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType&); +template void ObjectUpdater::Visit<AreaTrigger>(AreaTriggerMapType &); + diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index e9ba95f8fb6..d4b75b026f6 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -25,6 +25,7 @@ #include "Corpse.h" #include "Object.h" +#include "AreaTrigger.h" #include "DynamicObject.h" #include "GameObject.h" #include "Player.h" @@ -45,7 +46,7 @@ namespace Trinity std::set<Unit*> i_visibleNow; Player::ClientGUIDs vis_guids; - VisibleNotifier(Player &player) : i_player(player), vis_guids(player.m_clientGUIDs) { } + VisibleNotifier(Player &player) : i_player(player), i_data(player.GetMapId()), vis_guids(player.m_clientGUIDs) { } template<class T> void Visit(GridRefManager<T> &m); void SendToSelf(void); }; @@ -118,18 +119,18 @@ namespace Trinity void Visit(GameObjectMapType &m) { updateObjects<GameObject>(m); } void Visit(DynamicObjectMapType &m) { updateObjects<DynamicObject>(m); } void Visit(CorpseMapType &m) { updateObjects<Corpse>(m); } + void Visit(AreaTriggerMapType &m) { updateObjects<AreaTrigger>(m); } }; struct MessageDistDeliverer { WorldObject* i_source; WorldPacket* i_message; - uint32 i_phaseMask; float i_distSq; uint32 team; Player const* skipped_receiver; MessageDistDeliverer(WorldObject* src, WorldPacket* msg, float dist, bool own_team_only = false, Player const* skipped = NULL) - : i_source(src), i_message(msg), i_phaseMask(src->GetPhaseMask()), i_distSq(dist * dist) + : i_source(src), i_message(msg), i_distSq(dist * dist) , team(0) , skipped_receiver(skipped) { @@ -173,19 +174,20 @@ namespace Trinity template<class Check> struct WorldObjectSearcher { - uint32 i_mapTypeMask; - uint32 i_phaseMask; - WorldObject* &i_object; + WorldObject const* _searcher; + WorldObject*& i_object; Check &i_check; + uint32 i_mapTypeMask; WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) - : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check), i_mapTypeMask(mapTypeMask) { } void Visit(GameObjectMapType &m); void Visit(PlayerMapType &m); void Visit(CreatureMapType &m); void Visit(CorpseMapType &m); void Visit(DynamicObjectMapType &m); + void Visit(AreaTriggerMapType &m); template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) { } }; @@ -193,19 +195,20 @@ namespace Trinity template<class Check> struct WorldObjectLastSearcher { - uint32 i_mapTypeMask; - uint32 i_phaseMask; + WorldObject const* _searcher; WorldObject* &i_object; Check &i_check; + uint32 i_mapTypeMask; WorldObjectLastSearcher(WorldObject const* searcher, WorldObject* & result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) - : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check), i_mapTypeMask(mapTypeMask) { } void Visit(GameObjectMapType &m); void Visit(PlayerMapType &m); void Visit(CreatureMapType &m); void Visit(CorpseMapType &m); void Visit(DynamicObjectMapType &m); + void Visit(AreaTriggerMapType &m); template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) { } }; @@ -214,18 +217,19 @@ namespace Trinity struct WorldObjectListSearcher { uint32 i_mapTypeMask; - uint32 i_phaseMask; + WorldObject const* _searcher; std::list<WorldObject*> &i_objects; Check& i_check; WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*> &objects, Check & check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) - : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { } + : i_mapTypeMask(mapTypeMask), _searcher(searcher), i_objects(objects), i_check(check) { } void Visit(PlayerMapType &m); void Visit(CreatureMapType &m); void Visit(CorpseMapType &m); void Visit(GameObjectMapType &m); void Visit(DynamicObjectMapType &m); + void Visit(AreaTriggerMapType &m); template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) { } }; @@ -234,18 +238,18 @@ namespace Trinity struct WorldObjectWorker { uint32 i_mapTypeMask; - uint32 i_phaseMask; + WorldObject const* _searcher; Do const& i_do; WorldObjectWorker(WorldObject const* searcher, Do const& _do, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) - : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_do(_do) { } + : i_mapTypeMask(mapTypeMask), _searcher(searcher), i_do(_do) { } void Visit(GameObjectMapType &m) { if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT)) return; for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) i_do(itr->GetSource()); } @@ -254,7 +258,7 @@ namespace Trinity if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER)) return; for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) i_do(itr->GetSource()); } void Visit(CreatureMapType &m) @@ -262,7 +266,7 @@ namespace Trinity if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE)) return; for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) i_do(itr->GetSource()); } @@ -271,7 +275,7 @@ namespace Trinity if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE)) return; for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) i_do(itr->GetSource()); } @@ -280,7 +284,16 @@ namespace Trinity if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT)) return; for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) + i_do(itr->GetSource()); + } + + void Visit(AreaTriggerMapType &m) + { + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_AREATRIGGER)) + return; + for (AreaTriggerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->GetSource()->IsInPhase(_searcher)) i_do(itr->GetSource()); } @@ -292,12 +305,12 @@ namespace Trinity template<class Check> struct GameObjectSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; GameObject* &i_object; Check &i_check; GameObjectSearcher(WorldObject const* searcher, GameObject* & result, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check) { } void Visit(GameObjectMapType &m); @@ -308,12 +321,12 @@ namespace Trinity template<class Check> struct GameObjectLastSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; GameObject* &i_object; Check& i_check; GameObjectLastSearcher(WorldObject const* searcher, GameObject* & result, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check) { } void Visit(GameObjectMapType &m); @@ -323,12 +336,12 @@ namespace Trinity template<class Check> struct GameObjectListSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; std::list<GameObject*> &i_objects; Check& i_check; GameObjectListSearcher(WorldObject const* searcher, std::list<GameObject*> &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { } + : _searcher(searcher), i_objects(objects), i_check(check) { } void Visit(GameObjectMapType &m); @@ -339,12 +352,12 @@ namespace Trinity struct GameObjectWorker { GameObjectWorker(WorldObject const* searcher, Functor& func) - : _func(func), _phaseMask(searcher->GetPhaseMask()) { } + : _func(func), _searcher(searcher) { } void Visit(GameObjectMapType& m) { for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) _func(itr->GetSource()); } @@ -352,7 +365,7 @@ namespace Trinity private: Functor& _func; - uint32 _phaseMask; + WorldObject const* _searcher; }; // Unit searchers @@ -361,12 +374,12 @@ namespace Trinity template<class Check> struct UnitSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; Unit* &i_object; Check & i_check; UnitSearcher(WorldObject const* searcher, Unit* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check) { } void Visit(CreatureMapType &m); void Visit(PlayerMapType &m); @@ -378,12 +391,12 @@ namespace Trinity template<class Check> struct UnitLastSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; Unit* &i_object; Check & i_check; UnitLastSearcher(WorldObject const* searcher, Unit* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check) { } void Visit(CreatureMapType &m); void Visit(PlayerMapType &m); @@ -395,12 +408,12 @@ namespace Trinity template<class Check> struct UnitListSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; std::list<Unit*> &i_objects; Check& i_check; UnitListSearcher(WorldObject const* searcher, std::list<Unit*> &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { } + : _searcher(searcher), i_objects(objects), i_check(check) { } void Visit(PlayerMapType &m); void Visit(CreatureMapType &m); @@ -413,12 +426,12 @@ namespace Trinity template<class Check> struct CreatureSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; Creature* &i_object; Check & i_check; CreatureSearcher(WorldObject const* searcher, Creature* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check) { } void Visit(CreatureMapType &m); @@ -429,12 +442,12 @@ namespace Trinity template<class Check> struct CreatureLastSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; Creature* &i_object; Check & i_check; CreatureLastSearcher(WorldObject const* searcher, Creature* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check) { } void Visit(CreatureMapType &m); @@ -444,12 +457,12 @@ namespace Trinity template<class Check> struct CreatureListSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; std::list<Creature*> &i_objects; Check& i_check; CreatureListSearcher(WorldObject const* searcher, std::list<Creature*> &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { } + : _searcher(searcher), i_objects(objects), i_check(check) { } void Visit(CreatureMapType &m); @@ -459,16 +472,16 @@ namespace Trinity template<class Do> struct CreatureWorker { - uint32 i_phaseMask; + WorldObject const* _searcher; Do& i_do; CreatureWorker(WorldObject const* searcher, Do& _do) - : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) { } + : _searcher(searcher), i_do(_do) { } void Visit(CreatureMapType &m) { for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) i_do(itr->GetSource()); } @@ -480,12 +493,12 @@ namespace Trinity template<class Check> struct PlayerSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; Player* &i_object; Check & i_check; PlayerSearcher(WorldObject const* searcher, Player* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) { } + : _searcher(searcher), i_object(result), i_check(check) { } void Visit(PlayerMapType &m); @@ -495,12 +508,12 @@ namespace Trinity template<class Check> struct PlayerListSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; std::list<Player*> &i_objects; Check& i_check; PlayerListSearcher(WorldObject const* searcher, std::list<Player*> &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) { } + : _searcher(searcher), i_objects(objects), i_check(check) { } void Visit(PlayerMapType &m); @@ -510,11 +523,11 @@ namespace Trinity template<class Check> struct PlayerLastSearcher { - uint32 i_phaseMask; + WorldObject const* _searcher; Player* &i_object; Check& i_check; - PlayerLastSearcher(WorldObject const* searcher, Player*& result, Check& check) : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) + PlayerLastSearcher(WorldObject const* searcher, Player*& result, Check& check) : _searcher(searcher), i_object(result), i_check(check) { } @@ -526,16 +539,16 @@ namespace Trinity template<class Do> struct PlayerWorker { - uint32 i_phaseMask; + WorldObject const* _searcher; Do& i_do; PlayerWorker(WorldObject const* searcher, Do& _do) - : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) { } + : _searcher(searcher), i_do(_do) { } void Visit(PlayerMapType &m) { for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) i_do(itr->GetSource()); } @@ -555,7 +568,7 @@ namespace Trinity void Visit(PlayerMapType &m) { for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_searcher) && itr->GetSource()->IsWithinDist(i_searcher, i_dist)) + if (itr->GetSource()->IsInPhase(i_searcher) && itr->GetSource()->IsWithinDist(i_searcher, i_dist)) i_do(itr->GetSource()); } @@ -1330,7 +1343,7 @@ namespace Trinity AllWorldObjectsInRange(const WorldObject* object, float maxRange) : m_pObject(object), m_fRange(maxRange) { } bool operator() (WorldObject* go) { - return m_pObject->IsWithinDist(go, m_fRange, false) && m_pObject->InSamePhase(go); + return m_pObject->IsWithinDist(go, m_fRange, false) && m_pObject->IsInPhase(go); } private: const WorldObject* m_pObject; @@ -1364,6 +1377,25 @@ namespace Trinity uint64 _GUID; }; + class HeightDifferenceCheck + { + public: + HeightDifferenceCheck(WorldObject* go, float diff, bool reverse) + : _baseObject(go), _difference(diff), _reverse(reverse) + { + } + + bool operator()(WorldObject* unit) const + { + return (unit->GetPositionZ() - _baseObject->GetPositionZ() > _difference) != _reverse; + } + + private: + WorldObject* _baseObject; + float _difference; + bool _reverse; + }; + class UnitAuraCheck { public: diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index 77b49fdfc8b..e73f18abf90 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -54,7 +54,7 @@ void Trinity::WorldObjectSearcher<Check>::Visit(GameObjectMapType &m) for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -77,7 +77,7 @@ void Trinity::WorldObjectSearcher<Check>::Visit(PlayerMapType &m) for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -100,7 +100,7 @@ void Trinity::WorldObjectSearcher<Check>::Visit(CreatureMapType &m) for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -123,7 +123,7 @@ void Trinity::WorldObjectSearcher<Check>::Visit(CorpseMapType &m) for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -146,7 +146,7 @@ void Trinity::WorldObjectSearcher<Check>::Visit(DynamicObjectMapType &m) for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -157,6 +157,28 @@ void Trinity::WorldObjectSearcher<Check>::Visit(DynamicObjectMapType &m) } } +template<class Check> +void Trinity::WorldObjectSearcher<Check>::Visit(AreaTriggerMapType &m) +{ + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_AREATRIGGER)) + return; + + // already found + if (i_object) + return; + + for (AreaTriggerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->GetSource()->IsInPhase(_searcher)) + continue; + + if (i_check(itr->GetSource())) + { + i_object = itr->GetSource(); + return; + } + } +} template<class Check> void Trinity::WorldObjectLastSearcher<Check>::Visit(GameObjectMapType &m) @@ -166,7 +188,7 @@ void Trinity::WorldObjectLastSearcher<Check>::Visit(GameObjectMapType &m) for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -182,7 +204,7 @@ void Trinity::WorldObjectLastSearcher<Check>::Visit(PlayerMapType &m) for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -198,7 +220,7 @@ void Trinity::WorldObjectLastSearcher<Check>::Visit(CreatureMapType &m) for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -214,7 +236,7 @@ void Trinity::WorldObjectLastSearcher<Check>::Visit(CorpseMapType &m) for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -230,7 +252,23 @@ void Trinity::WorldObjectLastSearcher<Check>::Visit(DynamicObjectMapType &m) for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) + continue; + + if (i_check(itr->GetSource())) + i_object = itr->GetSource(); + } +} + +template<class Check> +void Trinity::WorldObjectLastSearcher<Check>::Visit(AreaTriggerMapType &m) +{ + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_AREATRIGGER)) + return; + + for (AreaTriggerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -293,6 +331,17 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType &m) i_objects.push_back(itr->GetSource()); } +template<class Check> +void Trinity::WorldObjectListSearcher<Check>::Visit(AreaTriggerMapType &m) +{ + if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_AREATRIGGER)) + return; + + for (AreaTriggerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (i_check(itr->GetSource())) + i_objects.push_back(itr->GetSource()); +} + // Gameobject searchers template<class Check> @@ -304,7 +353,7 @@ void Trinity::GameObjectSearcher<Check>::Visit(GameObjectMapType &m) for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -320,7 +369,7 @@ void Trinity::GameObjectLastSearcher<Check>::Visit(GameObjectMapType &m) { for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -332,7 +381,7 @@ template<class Check> void Trinity::GameObjectListSearcher<Check>::Visit(GameObjectMapType &m) { for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) if (i_check(itr->GetSource())) i_objects.push_back(itr->GetSource()); } @@ -348,7 +397,7 @@ void Trinity::UnitSearcher<Check>::Visit(CreatureMapType &m) for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -368,7 +417,7 @@ void Trinity::UnitSearcher<Check>::Visit(PlayerMapType &m) for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -384,7 +433,7 @@ void Trinity::UnitLastSearcher<Check>::Visit(CreatureMapType &m) { for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -397,7 +446,7 @@ void Trinity::UnitLastSearcher<Check>::Visit(PlayerMapType &m) { for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -409,7 +458,7 @@ template<class Check> void Trinity::UnitListSearcher<Check>::Visit(PlayerMapType &m) { for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) if (i_check(itr->GetSource())) i_objects.push_back(itr->GetSource()); } @@ -418,7 +467,7 @@ template<class Check> void Trinity::UnitListSearcher<Check>::Visit(CreatureMapType &m) { for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) if (i_check(itr->GetSource())) i_objects.push_back(itr->GetSource()); } @@ -434,7 +483,7 @@ void Trinity::CreatureSearcher<Check>::Visit(CreatureMapType &m) for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -450,7 +499,7 @@ void Trinity::CreatureLastSearcher<Check>::Visit(CreatureMapType &m) { for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -462,7 +511,7 @@ template<class Check> void Trinity::CreatureListSearcher<Check>::Visit(CreatureMapType &m) { for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) if (i_check(itr->GetSource())) i_objects.push_back(itr->GetSource()); } @@ -471,7 +520,7 @@ template<class Check> void Trinity::PlayerListSearcher<Check>::Visit(PlayerMapType &m) { for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->GetSource()->InSamePhase(i_phaseMask)) + if (itr->GetSource()->IsInPhase(_searcher)) if (i_check(itr->GetSource())) i_objects.push_back(itr->GetSource()); } @@ -485,7 +534,7 @@ void Trinity::PlayerSearcher<Check>::Visit(PlayerMapType &m) for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -501,7 +550,7 @@ void Trinity::PlayerLastSearcher<Check>::Visit(PlayerMapType& m) { for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr) { - if (!itr->GetSource()->InSamePhase(i_phaseMask)) + if (!itr->GetSource()->IsInPhase(_searcher)) continue; if (i_check(itr->GetSource())) @@ -526,7 +575,7 @@ void Trinity::LocalizedPacketDo<Builder>::operator()(Player* p) i_builder(*data, loc_idx); - ASSERT(data->GetOpcode() != MSG_NULL_ACTION); + ASSERT(data->GetOpcode() != NULL_OPCODE); i_data_cache[cache_idx] = data; } diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp index 51a1f2215f8..ab7a0e20512 100644 --- a/src/server/game/Grids/ObjectGridLoader.cpp +++ b/src/server/game/Grids/ObjectGridLoader.cpp @@ -24,6 +24,7 @@ #include "GameObject.h" #include "DynamicObject.h" #include "Corpse.h" +#include "AreaTrigger.h" #include "World.h" #include "CellImpl.h" #include "CreatureAI.h" @@ -258,7 +259,9 @@ template void ObjectGridUnloader::Visit(CreatureMapType &); template void ObjectGridUnloader::Visit(GameObjectMapType &); template void ObjectGridUnloader::Visit(DynamicObjectMapType &); template void ObjectGridUnloader::Visit(CorpseMapType &); +template void ObjectGridUnloader::Visit(AreaTriggerMapType &); template void ObjectGridCleaner::Visit(CreatureMapType &); template void ObjectGridCleaner::Visit<GameObject>(GameObjectMapType &); template void ObjectGridCleaner::Visit<DynamicObject>(DynamicObjectMapType &); template void ObjectGridCleaner::Visit<Corpse>(CorpseMapType &); +template void ObjectGridCleaner::Visit<AreaTrigger>(AreaTriggerMapType &); diff --git a/src/server/game/Grids/ObjectGridLoader.h b/src/server/game/Grids/ObjectGridLoader.h index 2ddc51848a8..1f351c6a0ba 100644 --- a/src/server/game/Grids/ObjectGridLoader.h +++ b/src/server/game/Grids/ObjectGridLoader.h @@ -40,6 +40,7 @@ class ObjectGridLoader void Visit(CreatureMapType &m); void Visit(CorpseMapType &) const { } void Visit(DynamicObjectMapType&) const { } + void Visit(AreaTriggerMapType &) const { } void LoadN(void); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 2e7633091f3..e6f0b0f459a 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -267,6 +267,37 @@ void Group::ConvertToRaid() player->UpdateForQuestWorldObjects(); } +void Group::ConvertToGroup() +{ + if (m_memberSlots.size() > 5) + return; // What message error should we send? + + m_groupType = GroupType(GROUPTYPE_NORMAL); + + if (m_subGroupsCounts) + { + delete[] m_subGroupsCounts; + m_subGroupsCounts = NULL; + } + + if (!isBGGroup() && !isBFGroup()) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE); + + stmt->setUInt8(0, uint8(m_groupType)); + stmt->setUInt32(1, m_dbStoreId); + + CharacterDatabase.Execute(stmt); + } + + SendUpdate(); + + // update quest related GO states (quest activity dependent from raid membership) + for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) + if (Player* player = ObjectAccessor::FindPlayer(citr->guid)) + player->UpdateForQuestWorldObjects(); +} + bool Group::AddInvite(Player* player) { if (!player || player->GetGroupInvite()) @@ -437,7 +468,7 @@ bool Group::AddMember(Player* player) // Broadcast new player group member fields to rest of the group player->SetFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); - UpdateData groupData; + UpdateData groupData(player->GetMapId()); WorldPacket groupDataPacket; // Broadcast group members' fields to player @@ -457,7 +488,7 @@ bool Group::AddMember(Player* player) if (member->HaveAtClient(player)) { - UpdateData newData; + UpdateData newData(player->GetMapId()); WorldPacket newDataPacket; player->BuildValuesUpdateBlockForPlayer(&newData, member); if (newData.HasData()) @@ -785,6 +816,7 @@ void Group::SendLootStartRoll(uint32 countDown, uint32 mapid, const Roll &r) data << uint32(r.itemCount); // items in stack data << uint32(countDown); // the countdown time to choose "need" or "greed" data << uint8(r.rollVoteMask); // roll type mask + data << uint8(r.totalPlayersRolling); // maybe the number of players rolling for it??? for (Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr != r.playerVote.end(); ++itr) { @@ -815,6 +847,7 @@ void Group::SendLootStartRollToPlayer(uint32 countDown, uint32 mapId, Player* p, if (!canNeed) voteMask &= ~ROLL_FLAG_TYPE_NEED; data << uint8(voteMask); // roll type mask + data << uint8(r.totalPlayersRolling); // maybe the number of players rolling for it??? p->GetSession()->SendPacket(&data); } @@ -828,7 +861,7 @@ void Group::SendLootRoll(uint64 sourceGuid, uint64 targetGuid, uint8 rollNumber, data << uint32(roll.itemid); // the itemEntryId for the item that shall be rolled for data << uint32(roll.itemRandomSuffix); // randomSuffix data << uint32(roll.itemRandomPropId); // Item random property ID - data << uint8(rollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number + data << uint32(rollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number data << uint8(rollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll data << uint8(0); // 1: "You automatically passed on: %s because you cannot loot that item." - Possibly used in need befor greed @@ -852,7 +885,7 @@ void Group::SendLootRollWon(uint64 sourceGuid, uint64 targetGuid, uint8 rollNumb data << uint32(roll.itemRandomSuffix); // randomSuffix data << uint32(roll.itemRandomPropId); // Item random property data << uint64(targetGuid); // guid of the player who won. - data << uint8(rollNumber); // rollnumber realted to SMSG_LOOT_ROLL + data << uint32(rollNumber); // rollnumber realted to SMSG_LOOT_ROLL data << uint8(rollType); // rollType related to SMSG_LOOT_ROLL for (Roll::PlayerVote::const_iterator itr = roll.playerVote.begin(); itr != roll.playerVote.end(); ++itr) @@ -1516,6 +1549,7 @@ void Group::SendUpdateToPlayer(uint64 playerGUID, MemberSlot* slot) { data << uint8(sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done data << uint32(sLFGMgr->GetDungeon(m_guid)); + data << uint8(0); // 4.x new } data << uint64(m_guid); @@ -1553,7 +1587,6 @@ void Group::SendUpdateToPlayer(uint64 playerGUID, MemberSlot* slot) data << uint8(m_lootThreshold); // loot threshold data << uint8(m_dungeonDifficulty); // Dungeon Difficulty data << uint8(m_raidDifficulty); // Raid Difficulty - data << uint8(m_raidDifficulty >= RAID_DIFFICULTY_10MAN_HEROIC); // 3.3 Dynamic Raid Difficulty - 0 normal/1 heroic } player->GetSession()->SendPacket(&data); @@ -1576,6 +1609,21 @@ void Group::UpdatePlayerOutOfRange(Player* player) } } +void Group::BroadcastAddonMessagePacket(WorldPacket* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group, uint64 ignore) +{ + for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* player = itr->GetSource(); + if (!player || (ignore != 0 && player->GetGUID() == ignore) || (ignorePlayersInBGRaid && player->GetGroup() != this)) + continue; + + if (WorldSession* session = player->GetSession()) + if (session && (group == -1 || itr->getSubGroup() == group)) + if (session->IsAddonRegistered(prefix)) + session->SendPacket(packet); + } +} + void Group::BroadcastPacket(WorldPacket* packet, bool ignorePlayersInBGRaid, int group, uint64 ignore) { for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) @@ -1784,7 +1832,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* BattlemasterListEntry const* bgEntry = sBattlemasterListStore.LookupEntry(bgOrTemplate->GetTypeID()); if (!bgEntry) - return ERR_GROUP_JOIN_BATTLEGROUND_FAIL; // shouldn't happen + return ERR_BATTLEGROUND_JOIN_FAILED; // shouldn't happen // check for min / max count uint32 memberscount = GetMembersCount(); @@ -1849,7 +1897,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* if (bgOrTemplate->isArena() && memberscount != MinPlayerCount) return ERR_ARENA_TEAM_PARTY_SIZE; - return GroupJoinBattlegroundResult(bgOrTemplate->GetTypeID()); + return ERR_BATTLEGROUND_NONE; } //=================================================== diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index f0061a70621..2929c05cace 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -94,34 +94,38 @@ enum GroupType enum GroupUpdateFlags { GROUP_UPDATE_FLAG_NONE = 0x00000000, // nothing - GROUP_UPDATE_FLAG_STATUS = 0x00000001, // uint16, flags - GROUP_UPDATE_FLAG_CUR_HP = 0x00000002, // uint32 - GROUP_UPDATE_FLAG_MAX_HP = 0x00000004, // uint32 - GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000008, // uint8 - GROUP_UPDATE_FLAG_CUR_POWER = 0x00000010, // uint16 - GROUP_UPDATE_FLAG_MAX_POWER = 0x00000020, // uint16 - GROUP_UPDATE_FLAG_LEVEL = 0x00000040, // uint16 - GROUP_UPDATE_FLAG_ZONE = 0x00000080, // uint16 - GROUP_UPDATE_FLAG_POSITION = 0x00000100, // uint16, uint16 - GROUP_UPDATE_FLAG_AURAS = 0x00000200, // uint64 mask, for each bit set uint32 spellid + uint8 unk - GROUP_UPDATE_FLAG_PET_GUID = 0x00000400, // uint64 pet guid - GROUP_UPDATE_FLAG_PET_NAME = 0x00000800, // pet name, NULL terminated string - GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00001000, // uint16, model id - GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00002000, // uint32 pet cur health - GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00004000, // uint32 pet max health - GROUP_UPDATE_FLAG_PET_POWER_TYPE = 0x00008000, // uint8 pet power type - GROUP_UPDATE_FLAG_PET_CUR_POWER = 0x00010000, // uint16 pet cur power - GROUP_UPDATE_FLAG_PET_MAX_POWER = 0x00020000, // uint16 pet max power - GROUP_UPDATE_FLAG_PET_AURAS = 0x00040000, // uint64 mask, for each bit set uint32 spellid + uint8 unk, pet auras... - GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00080000, // uint32 vehicle_seat_id (index from VehicleSeat.dbc) - GROUP_UPDATE_PET = 0x0007FC00, // all pet flags - GROUP_UPDATE_FULL = 0x0007FFFF // all known flags + GROUP_UPDATE_FLAG_STATUS = 0x00000001, // uint16 (GroupMemberStatusFlag) + GROUP_UPDATE_FLAG_CUR_HP = 0x00000002, // uint32 (HP) + GROUP_UPDATE_FLAG_MAX_HP = 0x00000004, // uint32 (HP) + GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000008, // uint8 (PowerType) + GROUP_UPDATE_FLAG_CUR_POWER = 0x00000010, // int16 (power value) + GROUP_UPDATE_FLAG_MAX_POWER = 0x00000020, // int16 (power value) + GROUP_UPDATE_FLAG_LEVEL = 0x00000040, // uint16 (level value) + GROUP_UPDATE_FLAG_ZONE = 0x00000080, // uint16 (zone id) + GROUP_UPDATE_FLAG_UNK100 = 0x00000100, // int16 (unk) + GROUP_UPDATE_FLAG_POSITION = 0x00000200, // uint16 (x), uint16 (y), uint16 (z) + GROUP_UPDATE_FLAG_AURAS = 0x00000400, // uint8 (unk), uint64 (mask), uint32 (count), for each bit set: uint32 (spell id) + uint16 (AuraFlags) (if has flags Scalable -> 3x int32 (bps)) + GROUP_UPDATE_FLAG_PET_GUID = 0x00000800, // uint64 (pet guid) + GROUP_UPDATE_FLAG_PET_NAME = 0x00001000, // cstring (name, NULL terminated string) + GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00002000, // uint16 (model id) + GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00004000, // uint32 (HP) + GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00008000, // uint32 (HP) + GROUP_UPDATE_FLAG_PET_POWER_TYPE = 0x00010000, // uint8 (PowerType) + GROUP_UPDATE_FLAG_PET_CUR_POWER = 0x00020000, // uint16 (power value) + GROUP_UPDATE_FLAG_PET_MAX_POWER = 0x00040000, // uint16 (power value) + GROUP_UPDATE_FLAG_PET_AURAS = 0x00080000, // [see GROUP_UPDATE_FLAG_AURAS] + GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00100000, // int32 (vehicle seat id) + GROUP_UPDATE_FLAG_PHASE = 0x00200000, // int32 (unk), uint32 (phase count), for (count) uint16(phaseId) + + GROUP_UPDATE_PET = GROUP_UPDATE_FLAG_PET_GUID | GROUP_UPDATE_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | + GROUP_UPDATE_FLAG_PET_CUR_HP | GROUP_UPDATE_FLAG_PET_MAX_HP | GROUP_UPDATE_FLAG_PET_POWER_TYPE | + GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER | GROUP_UPDATE_FLAG_PET_AURAS, // all pet flags + GROUP_UPDATE_FULL = GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP | + GROUP_UPDATE_FLAG_POWER_TYPE | GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER | + GROUP_UPDATE_FLAG_LEVEL | GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_POSITION | + GROUP_UPDATE_FLAG_AURAS | GROUP_UPDATE_PET | GROUP_UPDATE_FLAG_PHASE // all known flags, except UNK100 and VEHICLE_SEAT }; -#define GROUP_UPDATE_FLAGS_COUNT 20 - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 -static const uint8 GroupUpdateLength[GROUP_UPDATE_FLAGS_COUNT] = { 0, 2, 2, 2, 1, 2, 2, 2, 2, 4, 8, 8, 1, 2, 2, 2, 1, 2, 2, 8}; - class Roll : public LootValidatorRef { public: @@ -242,6 +246,7 @@ class Group void ConvertToLFG(); void ConvertToRaid(); + void ConvertToGroup(); void SetBattlegroundGroup(Battleground* bg); void SetBattlefieldGroup(Battlefield* bf); @@ -270,6 +275,7 @@ class Group void UpdatePlayerOutOfRange(Player* player); // ignore: GUID of player that will be ignored void BroadcastPacket(WorldPacket* packet, bool ignorePlayersInBGRaid, int group = -1, uint64 ignore = 0); + void BroadcastAddonMessagePacket(WorldPacket* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group = -1, uint64 ignore = 0); void BroadcastReadyCheck(WorldPacket* packet); void OfflineReadyCheck(); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 57e9a84d611..9e86039e4af 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -22,6 +22,7 @@ #include "Config.h" #include "DatabaseEnv.h" #include "Guild.h" +#include "GuildFinderMgr.h" #include "GuildMgr.h" #include "Language.h" #include "Log.h" @@ -73,7 +74,7 @@ std::string _GetGuildEventString(GuildEvents event) case GE_BANK_MONEY_SET: return "Bank money set"; case GE_BANK_TAB_AND_MONEY_UPDATED: - return "Bank and money updated"; + return "Bank money changed"; case GE_BANK_TEXT_CHANGED: return "Bank tab text changed"; default: @@ -98,7 +99,10 @@ inline uint32 _GetGuildBankTabPrice(uint8 tabId) void Guild::SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string const& param) { - WorldPacket data(SMSG_GUILD_COMMAND_RESULT, 8 + param.size() + 1); + // Note: SMSG_GUILD_COMMAND_RESULT and SMSG_GUILD_COMMAND_RESULT_2 do exactly the same in the client, they just have different structures. + // There's no particular reason why we use SMSG_GUILD_COMMAND_RESULT_2, this one is processed inmediately as it is read from the client. + // SMSG_GUILD_COMMAND_RESULT is a JAM opcode + WorldPacket data(SMSG_GUILD_COMMAND_RESULT_2, 8 + param.size() + 1); data << uint32(type); data << param; data << uint32(errCode); @@ -153,9 +157,13 @@ inline void Guild::LogHolder::AddEvent(SQLTransaction& trans, LogEntry* entry) // Writes information about all events into packet. inline void Guild::LogHolder::WritePacket(WorldPacket& data) const { - data << uint8(m_log.size()); + ByteBuffer buffer; + data.WriteBits(m_log.size(), 23); for (GuildLog::const_iterator itr = m_log.begin(); itr != m_log.end(); ++itr) - (*itr)->WritePacket(data); + (*itr)->WritePacket(data, buffer); + + data.FlushBits(); + data.append(buffer); } inline uint32 Guild::LogHolder::GetNextGUID() @@ -189,20 +197,56 @@ void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Guild::EventLogEntry::WritePacket(WorldPacket& data) const +void Guild::EventLogEntry::WritePacket(WorldPacket& data, ByteBuffer& content) const { - // Event type - data << uint8(m_eventType); - // Player 1 - data << uint64(MAKE_NEW_GUID(m_playerGuid1, 0, HIGHGUID_PLAYER)); - // Player 2 not for left/join guild events - if (m_eventType != GUILD_EVENT_LOG_JOIN_GUILD && m_eventType != GUILD_EVENT_LOG_LEAVE_GUILD) - data << uint64(MAKE_NEW_GUID(m_playerGuid2, 0, HIGHGUID_PLAYER)); - // New Rank - only for promote/demote guild events - if (m_eventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || m_eventType == GUILD_EVENT_LOG_DEMOTE_PLAYER) - data << uint8(m_newRank); + ObjectGuid guid1 = MAKE_NEW_GUID(m_playerGuid1, 0, HIGHGUID_PLAYER); + ObjectGuid guid2 = MAKE_NEW_GUID(m_playerGuid2, 0, HIGHGUID_PLAYER); + + data.WriteBit(guid1[2]); + data.WriteBit(guid1[4]); + data.WriteBit(guid2[7]); + data.WriteBit(guid2[6]); + data.WriteBit(guid1[3]); + data.WriteBit(guid2[3]); + data.WriteBit(guid2[5]); + data.WriteBit(guid1[7]); + data.WriteBit(guid1[5]); + data.WriteBit(guid1[0]); + data.WriteBit(guid2[4]); + data.WriteBit(guid2[2]); + data.WriteBit(guid2[0]); + data.WriteBit(guid2[1]); + data.WriteBit(guid1[1]); + data.WriteBit(guid1[6]); + + content.WriteByteSeq(guid2[3]); + content.WriteByteSeq(guid2[2]); + content.WriteByteSeq(guid2[5]); + + // New Rank + content << uint8(m_newRank); + + content.WriteByteSeq(guid2[4]); + content.WriteByteSeq(guid1[0]); + content.WriteByteSeq(guid1[4]); + // Event timestamp - data << uint32(::time(NULL) - m_timestamp); + content << uint32(::time(NULL) - m_timestamp); + + content.WriteByteSeq(guid1[7]); + content.WriteByteSeq(guid1[3]); + content.WriteByteSeq(guid2[0]); + content.WriteByteSeq(guid2[6]); + content.WriteByteSeq(guid2[7]); + content.WriteByteSeq(guid1[5]); + + // Event type + content << uint8(m_eventType); + + content.WriteByteSeq(guid2[1]); + content.WriteByteSeq(guid1[2]); + content.WriteByteSeq(guid1[6]); + content.WriteByteSeq(guid1[1]); } // BankEventLogEntry @@ -230,29 +274,101 @@ void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Guild::BankEventLogEntry::WritePacket(WorldPacket& data) const +void Guild::BankEventLogEntry::WritePacket(WorldPacket& data, ByteBuffer& content) const { - data << uint8(m_eventType); - data << uint64(MAKE_NEW_GUID(m_playerGuid, 0, HIGHGUID_PLAYER)); + ObjectGuid logGuid = MAKE_NEW_GUID(m_playerGuid, 0, HIGHGUID_PLAYER); - switch (m_eventType) - { - case GUILD_BANK_LOG_DEPOSIT_ITEM: - case GUILD_BANK_LOG_WITHDRAW_ITEM: - data << uint32(m_itemOrMoney); - data << uint32(m_itemStackCount); - break; - case GUILD_BANK_LOG_MOVE_ITEM: - case GUILD_BANK_LOG_MOVE_ITEM2: - data << uint32(m_itemOrMoney); - data << uint32(m_itemStackCount); - data << uint8(m_destTabId); - break; - default: - data << uint32(m_itemOrMoney); - } + bool hasItem = m_eventType == GUILD_BANK_LOG_DEPOSIT_ITEM || m_eventType == GUILD_BANK_LOG_WITHDRAW_ITEM || + m_eventType == GUILD_BANK_LOG_MOVE_ITEM || m_eventType == GUILD_BANK_LOG_MOVE_ITEM2; + + bool itemMoved = (m_eventType == GUILD_BANK_LOG_MOVE_ITEM || m_eventType == GUILD_BANK_LOG_MOVE_ITEM2); + + bool hasStack = (hasItem && m_itemStackCount > 1) || itemMoved; - data << uint32(time(NULL) - m_timestamp); + data.WriteBit(IsMoneyEvent()); + data.WriteBit(logGuid[4]); + data.WriteBit(logGuid[1]); + data.WriteBit(hasItem); + data.WriteBit(hasStack); + data.WriteBit(logGuid[2]); + data.WriteBit(logGuid[5]); + data.WriteBit(logGuid[3]); + data.WriteBit(logGuid[6]); + data.WriteBit(logGuid[0]); + data.WriteBit(itemMoved); + data.WriteBit(logGuid[7]); + + content.WriteByteSeq(logGuid[6]); + content.WriteByteSeq(logGuid[1]); + content.WriteByteSeq(logGuid[5]); + if (hasStack) + content << uint32(m_itemStackCount); + + content << uint8(m_eventType); + content.WriteByteSeq(logGuid[2]); + content.WriteByteSeq(logGuid[4]); + content.WriteByteSeq(logGuid[0]); + content.WriteByteSeq(logGuid[7]); + content.WriteByteSeq(logGuid[3]); + if (hasItem) + content << uint32(m_itemOrMoney); + + content << uint32(time(NULL) - m_timestamp); + + if (IsMoneyEvent()) + content << uint64(m_itemOrMoney); + + if (itemMoved) + content << uint8(m_destTabId); +} + +void Guild::NewsLogEntry::SaveToDB(SQLTransaction& trans) const +{ + uint8 index = 0; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_NEWS); + stmt->setUInt32( index, m_guildId); + stmt->setUInt32(++index, GetGUID()); + stmt->setUInt8 (++index, GetType()); + stmt->setUInt32(++index, GetPlayerGuid()); + stmt->setUInt32(++index, GetFlags()); + stmt->setUInt32(++index, GetValue()); + stmt->setUInt64(++index, GetTimestamp()); + CharacterDatabase.ExecuteOrAppend(trans, stmt); +} + +void Guild::NewsLogEntry::WritePacket(WorldPacket& data, ByteBuffer& /*content*/) const +{ + data.WriteBits(0, 26); // Not yet implemented used for guild achievements + ObjectGuid guid = GetPlayerGuid(); + + data.WriteBit(guid[7]); + data.WriteBit(guid[0]); + data.WriteBit(guid[6]); + data.WriteBit(guid[5]); + data.WriteBit(guid[4]); + data.WriteBit(guid[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[2]); + + data.FlushBits(); + + data.WriteByteSeq(guid[5]); + + data << uint32(GetFlags()); // 1 sticky + data << uint32(GetValue()); + data << uint32(0); // always 0 + + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[1]); + + data << uint32(GetGUID()); + data << uint32(GetType()); + data.AppendPackedTime(GetTimestamp()); } // RankInfo @@ -302,20 +418,6 @@ void Guild::RankInfo::CreateMissingTabsIfNeeded(uint8 tabs, SQLTransaction& tran } } -void Guild::RankInfo::WritePacket(WorldPacket& data) const -{ - data << uint32(m_rights); - if (m_bankMoneyPerDay == GUILD_WITHDRAW_MONEY_UNLIMITED) - data << uint32(GUILD_WITHDRAW_MONEY_UNLIMITED); - else - data << uint32(m_bankMoneyPerDay); - for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - data << uint32(m_bankTabRightsAndSlots[i].GetRights()); - data << uint32(m_bankTabRightsAndSlots[i].GetSlots()); - } -} - void Guild::RankInfo::SetName(std::string const& name) { if (m_name == name) @@ -444,64 +546,6 @@ void Guild::BankTab::Delete(SQLTransaction& trans, bool removeItemsFromDB) } } -inline void Guild::BankTab::WritePacket(WorldPacket& data) const -{ - uint8 count = 0; - - size_t pos = data.wpos(); - data << uint8(0); - - for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) - if (WriteSlotPacket(data, slotId)) - ++count; - - data.put<uint8>(pos, count); -} - -// Writes information about contents of specified slot into packet. -bool Guild::BankTab::WriteSlotPacket(WorldPacket& data, uint8 slotId, bool ignoreEmpty /* = true */) const -{ - Item* pItem = GetItem(slotId); - uint32 itemEntry = pItem ? pItem->GetEntry() : 0; - - if (!itemEntry && ignoreEmpty) - return false; - - data << uint8(slotId); - data << uint32(itemEntry); - if (itemEntry) - { - data << uint32(0); // 3.3.0 (0x00018020, 0x00018000) - - - if (uint32 random = pItem->GetItemRandomPropertyId()) - { - data << uint32(random); // Random item property id - data << uint32(pItem->GetItemSuffixFactor()); // SuffixFactor - } - else - data << uint32(0); - - data << uint32(pItem->GetCount()); // ITEM_FIELD_STACK_COUNT - data << uint32(0); - data << uint8(abs(pItem->GetSpellCharges())); // Spell charges - - uint8 enchCount = 0; - size_t enchCountPos = data.wpos(); - - data << uint8(enchCount); // Number of enchantments - for (uint32 i = PERM_ENCHANTMENT_SLOT; i < MAX_ENCHANTMENT_SLOT; ++i) - if (uint32 enchId = pItem->GetEnchantmentId(EnchantmentSlot(i))) - { - data << uint8(i); - data << uint32(enchId); - ++enchCount; - } - data.put<uint8>(enchCountPos, enchCount); - } - return true; -} - void Guild::BankTab::SetInfo(std::string const& name, std::string const& icon) { if (m_name == name && m_icon == icon) @@ -567,19 +611,20 @@ bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item) void Guild::BankTab::SendText(Guild const* guild, WorldSession* session) const { - WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1 + m_text.size() + 1); - data << uint8(m_tabId); - data << m_text; + WorldPacket data(SMSG_GUILD_BANK_QUERY_TEXT_RESULT, 1 + m_text.size() + 1); + data.WriteBits(m_text.length(), 14); + data << uint32(m_tabId); + data.WriteString(m_text); if (session) { - TC_LOG_DEBUG("guild", "MSG_QUERY_GUILD_BANK_TEXT [%s]: Tabid: %u, Text: %s" + TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_QUERY_TEXT_RESULT [%s]: Tabid: %u, Text: %s" , session->GetPlayerInfo().c_str(), m_tabId, m_text.c_str()); session->SendPacket(&data); } else { - TC_LOG_DEBUG("guild", "MSG_QUERY_GUILD_BANK_TEXT [Broadcast]: Tabid: %u, Text: %s", m_tabId, m_text.c_str()); + TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_QUERY_TEXT_RESULT [Broadcast]: Tabid: %u, Text: %s", m_tabId, m_text.c_str()); guild->BroadcastPacket(&data); } } @@ -592,15 +637,17 @@ void Guild::Member::SetStats(Player* player) m_class = player->getClass(); m_zoneId = player->GetZoneId(); m_accountId = player->GetSession()->GetAccountId(); + m_achievementPoints = player->GetAchievementPoints(); } -void Guild::Member::SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId) +void Guild::Member::SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId, uint32 reputation) { m_name = name; m_level = level; m_class = _class; m_zoneId = zoneId; m_accountId = accountId; + m_totalReputation = reputation; } void Guild::Member::SetPublicNote(std::string const& publicNote) @@ -665,12 +712,16 @@ bool Guild::Member::LoadFromDB(Field* fields) for (uint8 i = 0; i <= GUILD_BANK_MAX_TABS; ++i) m_bankWithdraw[i] = fields[5 + i].GetUInt32(); - SetStats(fields[12].GetString(), - fields[13].GetUInt8(), // characters.level - fields[14].GetUInt8(), // characters.class - fields[15].GetUInt16(), // characters.zone - fields[16].GetUInt32()); // characters.account - m_logoutTime = fields[17].GetUInt32(); // characters.logout_time + SetStats(fields[14].GetString(), + fields[15].GetUInt8(), // characters.level + fields[16].GetUInt8(), // characters.class + fields[17].GetUInt16(), // characters.zone + fields[18].GetUInt32(), // characters.account + 0); + m_logoutTime = fields[19].GetUInt32(); // characters.logout_time + m_totalActivity = 0; + m_weekActivity = 0; + m_weekReputation = 0; if (!CheckStats()) return false; @@ -701,28 +752,6 @@ bool Guild::Member::CheckStats() const return true; } -void Guild::Member::WritePacket(WorldPacket& data, bool sendOfficerNote) const -{ - data << uint64(m_guid) - << uint8(m_flags) - << m_name - << uint32(m_rankId) - << uint8(m_level) - << uint8(m_class) - << uint8(0) - << uint32(m_zoneId); - - if (!m_flags) - data << float(float(::time(NULL) - m_logoutTime) / DAY); - - data << m_publicNote; - - if (sendOfficerNote) - data << m_officerNote; - else - data << ""; -} - // Decreases amount of money/slots left for today. // If (tabId == GUILD_BANK_MAX_TABS) decrease money amount. // Otherwise decrease remaining items amount for specified tab. @@ -741,10 +770,16 @@ void Guild::Member::UpdateBankWithdrawValue(SQLTransaction& trans, uint8 tabId, CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Guild::Member::ResetValues() +void Guild::Member::ResetValues(bool weekly /* = false*/) { for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId) m_bankWithdraw[tabId] = 0; + + if (weekly) + { + m_weekActivity = 0; + m_weekReputation = 0; + } } // Get amount of money/slots left for today. @@ -851,13 +886,13 @@ bool Guild::PlayerMoveItemData::InitItem() // Anti-WPE protection. Do not move non-empty bags to bank. if (m_pItem->IsNotEmptyBag()) { - m_pPlayer->SendEquipError(EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS, m_pItem); + m_pPlayer->SendEquipError(EQUIP_ERR_DESTROY_NONEMPTY_BAG, m_pItem); m_pItem = NULL; } // Bound items cannot be put into bank. else if (!m_pItem->CanBeTraded()) { - m_pPlayer->SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, m_pItem); + m_pPlayer->SendEquipError(EQUIP_ERR_CANT_SWAP, m_pItem); m_pItem = NULL; } } @@ -1082,11 +1117,11 @@ InventoryResult Guild::BankMoveItemData::CanStore(Item* pItem, bool swap) uint32 count = pItem->GetCount(); // Soulbound items cannot be moved if (pItem->IsSoulBound()) - return EQUIP_ERR_CANT_DROP_SOULBOUND; + return EQUIP_ERR_DROP_BOUND_ITEM; // Make sure destination bank tab exists if (m_container >= m_pGuild->_GetPurchasedTabsSize()) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + return EQUIP_ERR_WRONG_BAG_TYPE; // Slot explicitely specified. Check it. if (m_slotId != NULL_SLOT) @@ -1097,7 +1132,7 @@ InventoryResult Guild::BankMoveItemData::CanStore(Item* pItem, bool swap) pItemDest = NULL; if (!_ReserveSpace(m_slotId, pItem, pItemDest, count)) - return EQUIP_ERR_ITEM_CANT_STACK; + return EQUIP_ERR_CANT_STACK; if (count == 0) return EQUIP_ERR_OK; @@ -1127,7 +1162,12 @@ Guild::Guild(): m_createdDate(0), m_accountsNumber(0), m_bankMoney(0), - m_eventLog(NULL) + m_eventLog(NULL), + m_newsLog(NULL), + m_achievementMgr(this), + _level(1), + _experience(0), + _todayExperience(0) { memset(&m_bankEventLog, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(LogHolder*)); } @@ -1140,6 +1180,8 @@ Guild::~Guild() // Cleanup delete m_eventLog; m_eventLog = NULL; + delete m_newsLog; + m_newsLog = NULL; for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId) { @@ -1172,6 +1214,9 @@ bool Guild::Create(Player* pLeader, std::string const& name) m_motd = "No message set."; m_bankMoney = 0; m_createdDate = ::time(NULL); + _level = 1; + _experience = 0; + _todayExperience = 0; _CreateLogHolders(); TC_LOG_DEBUG("guild", "GUILD: creating guild [%s] for leader %s (%u)", @@ -1204,7 +1249,10 @@ bool Guild::Create(Player* pLeader, std::string const& name) bool ret = AddMember(m_leaderGuid, GR_GUILDMASTER); // Add guildmaster if (ret) + { + _BroadcastEvent(GE_FOUNDER, 0); sScriptMgr->OnGuildCreate(this, pLeader, name); + } return ret; } @@ -1257,9 +1305,28 @@ void Guild::Disband() trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); + + sGuildFinderMgr->DeleteGuild(m_id); + sGuildMgr->RemoveGuild(m_id); } +void Guild::SaveToDB() +{ + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_EXPERIENCE); + stmt->setUInt32(0, GetLevel()); + stmt->setUInt64(1, GetExperience()); + stmt->setUInt64(2, GetTodayExperience()); + stmt->setUInt32(3, GetId()); + trans->Append(stmt); + + m_achievementMgr.SaveToDB(trans); + + CharacterDatabase.CommitTransaction(trans); +} + void Guild::UpdateMemberData(Player* player, uint8 dataid, uint32 value) { if (Member* member = GetMember(player->GetGUID())) @@ -1267,7 +1334,10 @@ void Guild::UpdateMemberData(Player* player, uint8 dataid, uint32 value) switch (dataid) { case GUILD_MEMBER_DATA_ZONEID: - member->SetZoneID(value); + member->SetZoneId(value); + break; + case GUILD_MEMBER_DATA_ACHIEVEMENT_POINTS: + member->SetAchievementPoints(value); break; case GUILD_MEMBER_DATA_LEVEL: member->SetLevel(value); @@ -1300,23 +1370,113 @@ bool Guild::SetName(std::string const& name) stmt->setString(0, m_name); stmt->setUInt32(1, GetId()); CharacterDatabase.Execute(stmt); + + ObjectGuid guid = GetGUID(); + WorldPacket data(SMSG_GUILD_RENAMED, 24 + 8 + 1); + data.WriteBit(guid[5]); + data.WriteBits(name.length(), 8); + data.WriteBit(guid[4]); + data.WriteBit(guid[0]); + data.WriteBit(guid[6]); + data.WriteBit(guid[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[7]); + data.WriteBit(guid[2]); + + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[6]); + data.WriteString(name); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[5]); + + BroadcastPacket(&data); return true; } void Guild::HandleRoster(WorldSession* session) { + ByteBuffer memberData(100); // Guess size - WorldPacket data(SMSG_GUILD_ROSTER, (4 + m_motd.length() + 1 + m_info.length() + 1 + 4 + _GetRanksSize() * (4 + 4 + GUILD_BANK_MAX_TABS * (4 + 4)) + m_members.size() * 50)); - data << uint32(m_members.size()); - data << m_motd; - data << m_info; - - data << uint32(_GetRanksSize()); - for (Ranks::const_iterator ritr = m_ranks.begin(); ritr != m_ranks.end(); ++ritr) - ritr->WritePacket(data); + WorldPacket data(SMSG_GUILD_ROSTER, 100); + data.WriteBits(m_motd.length(), 11); + data.WriteBits(m_members.size(), 18); for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) - itr->second->WritePacket(data, _HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE)); + { + Member* member = itr->second; + size_t pubNoteLength = member->GetPublicNote().length(); + size_t offNoteLength = member->GetOfficerNote().length(); + + ObjectGuid guid = member->GetGUID(); + data.WriteBit(guid[3]); + data.WriteBit(guid[4]); + data.WriteBit(0); // Has Authenticator + data.WriteBit(0); // Can Scroll of Ressurect + data.WriteBits(pubNoteLength, 8); + data.WriteBits(offNoteLength, 8); + data.WriteBit(guid[0]); + data.WriteBits(member->GetName().length(), 7); + data.WriteBit(guid[1]); + data.WriteBit(guid[2]); + data.WriteBit(guid[6]); + data.WriteBit(guid[5]); + data.WriteBit(guid[7]); + + memberData << uint8(member->GetClass()); + memberData << uint32(member->GetTotalReputation()); + memberData.WriteByteSeq(guid[0]); + memberData << uint64(member->GetWeekActivity()); + memberData << uint32(member->GetRankId()); + memberData << uint32(member->GetAchievementPoints()); + + // for (2 professions) + memberData << uint32(0) << uint32(0) << uint32(0); + memberData << uint32(0) << uint32(0) << uint32(0); + + memberData.WriteByteSeq(guid[2]); + memberData << uint8(member->GetFlags()); + memberData << uint32(member->GetZoneId()); + memberData << uint64(member->GetTotalActivity()); + memberData.WriteByteSeq(guid[7]); + memberData << uint32(sWorld->getIntConfig(CONFIG_GUILD_WEEKLY_REP_CAP) - member->GetWeekReputation()); + + if (pubNoteLength) + memberData.WriteString(member->GetPublicNote()); + + memberData.WriteByteSeq(guid[3]); + memberData << uint8(member->GetLevel()); + memberData << int32(0); // unk + memberData.WriteByteSeq(guid[5]); + memberData.WriteByteSeq(guid[4]); + memberData << uint8(0); // unk + memberData.WriteByteSeq(guid[1]); + memberData << float(member->IsOnline() ? 0.0f : float(::time(NULL) - member->GetLogoutTime()) / DAY); + + if (offNoteLength) + memberData.WriteString(member->GetOfficerNote()); + + memberData.WriteByteSeq(guid[6]); + memberData.WriteString(member->GetName()); + } + + size_t infoLength = m_info.length(); + data.WriteBits(infoLength, 12); + + data.FlushBits(); + data.append(memberData); + + if (infoLength) + data.WriteString(m_info); + + data.WriteString(m_motd); + data << uint32(m_accountsNumber); + data << uint32(sWorld->getIntConfig(CONFIG_GUILD_WEEKLY_REP_CAP)); + data.AppendPackedTime(m_createdDate); + data << uint32(0); TC_LOG_DEBUG("guild", "SMSG_GUILD_ROSTER [%s]", session->GetPlayerInfo().c_str()); session->SendPacket(&data); @@ -1325,7 +1485,8 @@ void Guild::HandleRoster(WorldSession* session) void Guild::HandleQuery(WorldSession* session) { WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, 8 * 32 + 200); // Guess size - data << uint32(m_id); + + data << uint64(GetGUID()); data << m_name; // Rank name @@ -1337,6 +1498,24 @@ void Guild::HandleQuery(WorldSession* session) data << uint8(0); // Empty string } + // Rank order of creation + for (uint8 i = 0; i < GUILD_RANKS_MAX_COUNT; ++i) + { + if (i < _GetRanksSize()) + data << uint32(i); + else + data << uint32(0); + } + + // Rank order of "importance" (sorting by rights) + for (uint8 i = 0; i < GUILD_RANKS_MAX_COUNT; ++i) + { + if (i < _GetRanksSize()) + data << uint32(m_ranks[i].GetId()); + else + data << uint32(0); + } + m_emblemInfo.WritePacket(data); data << uint32(_GetRanksSize()); // Number of ranks used @@ -1344,6 +1523,44 @@ void Guild::HandleQuery(WorldSession* session) TC_LOG_DEBUG("guild", "SMSG_GUILD_QUERY_RESPONSE [%s]", session->GetPlayerInfo().c_str()); } +void Guild::SendGuildRankInfo(WorldSession* session) const +{ + ByteBuffer rankData(100); + WorldPacket data(SMSG_GUILD_RANK, 100); + + data.WriteBits(_GetRanksSize(), 18); + + for (uint8 i = 0; i < _GetRanksSize(); i++) + { + RankInfo const* rankInfo = GetRankInfo(i); + if (!rankInfo) + continue; + + data.WriteBits(rankInfo->GetName().length(), 7); + + rankData << uint32(rankInfo->GetId()); + + for (uint8 j = 0; j < GUILD_BANK_MAX_TABS; ++j) + { + rankData << uint32(rankInfo->GetBankTabSlotsPerDay(j)); + rankData << uint32(rankInfo->GetBankTabRights(j)); + } + + rankData << uint32(rankInfo->GetBankMoneyPerDay()); + rankData << uint32(rankInfo->GetRights()); + + if (rankInfo->GetName().length()) + rankData.WriteString(rankInfo->GetName()); + + rankData << uint32(i); + } + + data.FlushBits(); + data.append(rankData); + session->SendPacket(&data); + TC_LOG_DEBUG("guild", "SMSG_GUILD_RANK [%s]", session->GetPlayerInfo().c_str()); +} + void Guild::HandleSetMOTD(WorldSession* session, std::string const& motd) { if (m_motd == motd) @@ -1391,11 +1608,11 @@ void Guild::HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo) Player* player = session->GetPlayer(); if (!_IsLeader(player)) SendSaveEmblemResult(session, ERR_GUILDEMBLEM_NOTGUILDMASTER); // "Only guild leaders can create emblems." - else if (!player->HasEnoughMoney(EMBLEM_PRICE)) + else if (!player->HasEnoughMoney(uint64(EMBLEM_PRICE))) SendSaveEmblemResult(session, ERR_GUILDEMBLEM_NOTENOUGHMONEY); // "You can't afford to do that." else { - player->ModifyMoney(-int32(EMBLEM_PRICE)); + player->ModifyMoney(-int64(EMBLEM_PRICE)); m_emblemInfo = emblemInfo; m_emblemInfo.SaveToDB(m_id); @@ -1406,20 +1623,20 @@ void Guild::HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo) } } -void Guild::HandleSetLeader(WorldSession* session, std::string const& name) +void Guild::HandleSetNewGuildMaster(WorldSession* session, std::string const& name) { Player* player = session->GetPlayer(); - // Only leader can assign new leader + // Only the guild master can throne a new guild master if (!_IsLeader(player)) SendCommandResult(session, GUILD_COMMAND_CHANGE_LEADER, ERR_GUILD_PERMISSIONS); - // Old leader must be a member of guild - else if (Member* pOldLeader = GetMember(player->GetGUID())) + // Old GM must be a guild member + else if (Member* oldGuildMaster = GetMember(player->GetGUID())) { - // New leader must be a member of guild - if (Member* pNewLeader = GetMember(name)) + // Same for the new one + if (Member* newGuildMaster = GetMember(name)) { - _SetLeaderGUID(pNewLeader); - pOldLeader->ChangeRank(GR_OFFICER); + _SetLeaderGUID(newGuildMaster); + oldGuildMaster->ChangeRank(GR_INITIATE); _BroadcastEvent(GE_LEADER_CHANGED, 0, player->GetName().c_str(), name.c_str()); } } @@ -1442,19 +1659,19 @@ void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string _BroadcastEvent(GE_BANK_TAB_UPDATED, 0, aux, name.c_str(), icon.c_str()); } -void Guild::HandleSetMemberNote(WorldSession* session, std::string const& name, std::string const& note, bool isPublic) +void Guild::HandleSetMemberNote(WorldSession* session, std::string const& note, uint64 guid, bool isPublic) { // Player must have rights to set public/officer note if (!_HasRankRight(session->GetPlayer(), isPublic ? GR_RIGHT_EPNOTE : GR_RIGHT_EOFFNOTE)) SendCommandResult(session, GUILD_COMMAND_PUBLIC_NOTE, ERR_GUILD_PERMISSIONS); - else if (Member* member = GetMember(name)) + else if (Member* member = GetMember(guid)) { if (isPublic) member->SetPublicNote(note); else member->SetOfficerNote(note); - HandleRoster(session); + HandleRoster(session); // FIXME - We should send SMSG_GUILD_MEMBER_UPDATE_NOTE } } @@ -1476,7 +1693,7 @@ void Guild::HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string c char aux[2]; sprintf(aux, "%u", rankId); - _BroadcastEvent(GE_RANK_UPDATED, 0, aux, name.c_str()); + _BroadcastEvent(GE_RANK_UPDATED, 0, aux); } } @@ -1496,14 +1713,19 @@ void Guild::HandleBuyBankTab(WorldSession* session, uint8 tabId) if (tabId != _GetPurchasedTabsSize()) return; - uint32 tabCost = _GetGuildBankTabPrice(tabId) * GOLD; - if (!tabCost) - return; + // Do not get money for bank tabs that the GM bought, we had to buy them already. + // This is just a speedup check, GetGuildBankTabPrice will return 0. + if (tabId < GUILD_BANK_MAX_TABS - 2) // 7th tab is actually the 6th + { + uint32 tabCost = _GetGuildBankTabPrice(tabId) * GOLD; + if (!tabCost) + return; - if (!player->HasEnoughMoney(tabCost)) // Should not happen, this is checked by client - return; + if (!player->HasEnoughMoney(uint64(tabCost))) // Should not happen, this is checked by client + return; - player->ModifyMoney(-int32(tabCost)); + player->ModifyMoney(-int64(tabCost)); + } _CreateNewBankTab(); _BroadcastEvent(GE_BANK_TAB_PURCHASED, 0); @@ -1529,12 +1751,14 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name) SendCommandResult(session, GUILD_COMMAND_INVITE, ERR_GUILD_NOT_ALLIED, name); return; } + // Invited player cannot be in another guild - if (pInvitee->GetGuildId()) + /*if (pInvitee->GetGuildId()) { SendCommandResult(session, GUILD_COMMAND_INVITE, ERR_ALREADY_IN_GUILD_S, name); return; - } + }*/ + // Invited player cannot be invited if (pInvitee->GetGuildIdInvited()) { @@ -1555,9 +1779,65 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name) pInvitee->SetGuildIdInvited(m_id); _LogEvent(GUILD_EVENT_LOG_INVITE_PLAYER, player->GetGUIDLow(), pInvitee->GetGUIDLow()); - WorldPacket data(SMSG_GUILD_INVITE, 8 + 10); // Guess size - data << player->GetName(); - data << m_name; + WorldPacket data(SMSG_GUILD_INVITE, 100); + data << uint32(GetLevel()); + data << uint32(m_emblemInfo.GetBorderStyle()); + data << uint32(m_emblemInfo.GetBorderColor()); + data << uint32(m_emblemInfo.GetStyle()); + data << uint32(m_emblemInfo.GetBackgroundColor()); + data << uint32(m_emblemInfo.GetColor()); + + ObjectGuid oldGuildGuid = MAKE_NEW_GUID(pInvitee->GetGuildId(), 0, pInvitee->GetGuildId() ? uint32(HIGHGUID_GUILD) : 0); + ObjectGuid newGuildGuid = GetGUID(); + + data.WriteBit(newGuildGuid[3]); + data.WriteBit(newGuildGuid[2]); + data.WriteBits(pInvitee->GetGuildName().length(), 8); + data.WriteBit(newGuildGuid[1]); + data.WriteBit(oldGuildGuid[6]); + data.WriteBit(oldGuildGuid[4]); + data.WriteBit(oldGuildGuid[1]); + data.WriteBit(oldGuildGuid[5]); + data.WriteBit(oldGuildGuid[7]); + data.WriteBit(oldGuildGuid[2]); + data.WriteBit(newGuildGuid[7]); + data.WriteBit(newGuildGuid[0]); + data.WriteBit(newGuildGuid[6]); + data.WriteBits(m_name.length(), 8); + data.WriteBit(oldGuildGuid[3]); + data.WriteBit(oldGuildGuid[0]); + data.WriteBit(newGuildGuid[5]); + data.WriteBits(player->GetName().size(), 7); + data.WriteBit(newGuildGuid[4]); + + data.FlushBits(); + + data.WriteByteSeq(newGuildGuid[1]); + data.WriteByteSeq(oldGuildGuid[3]); + data.WriteByteSeq(newGuildGuid[6]); + data.WriteByteSeq(oldGuildGuid[2]); + data.WriteByteSeq(oldGuildGuid[1]); + data.WriteByteSeq(newGuildGuid[0]); + + if (!pInvitee->GetGuildName().empty()) + data.WriteString(pInvitee->GetGuildName()); + + data.WriteByteSeq(newGuildGuid[7]); + data.WriteByteSeq(newGuildGuid[2]); + + data.WriteString(player->GetName()); + + data.WriteByteSeq(oldGuildGuid[7]); + data.WriteByteSeq(oldGuildGuid[6]); + data.WriteByteSeq(oldGuildGuid[5]); + data.WriteByteSeq(oldGuildGuid[0]); + data.WriteByteSeq(newGuildGuid[4]); + + data.WriteString(m_name); + + data.WriteByteSeq(newGuildGuid[5]); + data.WriteByteSeq(newGuildGuid[3]); + data.WriteByteSeq(oldGuildGuid[4]); pInvitee->GetSession()->SendPacket(&data); TC_LOG_DEBUG("guild", "SMSG_GUILD_INVITE [%s]", pInvitee->GetName().c_str()); } @@ -1583,6 +1863,8 @@ void Guild::HandleLeaveMember(WorldSession* session) if (m_members.size() > 1) // Leader cannot leave if he is not the last member SendCommandResult(session, GUILD_COMMAND_QUIT, ERR_GUILD_LEADER_LEAVE); + else if (GetLevel() >= sWorld->getIntConfig(CONFIG_GUILD_UNDELETABLE_LEVEL)) + SendCommandResult(session, GUILD_COMMAND_QUIT, ERR_GUILD_UNDELETABLE_DUE_TO_LEVEL); else { // Guild is disbanded if leader leaves. @@ -1606,14 +1888,17 @@ void Guild::HandleLeaveMember(WorldSession* session) delete this; } -void Guild::HandleRemoveMember(WorldSession* session, std::string const& name) +void Guild::HandleRemoveMember(WorldSession* session, uint64 guid) { Player* player = session->GetPlayer(); + // Player must have rights to remove members if (!_HasRankRight(player, GR_RIGHT_REMOVE)) SendCommandResult(session, GUILD_COMMAND_REMOVE, ERR_GUILD_PERMISSIONS); - else if (Member* member = GetMember(name)) + else if (Member* member = GetMember(guid)) { + std::string name = member->GetName(); + // Guild masters cannot be removed if (member->IsRank(GR_GUILDMASTER)) SendCommandResult(session, GUILD_COMMAND_REMOVE, ERR_GUILD_LEADER_LEAVE); @@ -1625,17 +1910,17 @@ void Guild::HandleRemoveMember(WorldSession* session, std::string const& name) SendCommandResult(session, GUILD_COMMAND_REMOVE, ERR_GUILD_RANK_TOO_HIGH_S, name); else { - uint64 guid = member->GetGUID(); // After call to DeleteMember pointer to member becomes invalid DeleteMember(guid, false, true); _LogEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, player->GetGUIDLow(), GUID_LOPART(guid)); _BroadcastEvent(GE_REMOVED, 0, name.c_str(), player->GetName().c_str()); + SendCommandResult(session, GUILD_COMMAND_REMOVE, ERR_GUILD_COMMAND_SUCCESS, name); } } } } -void Guild::HandleUpdateMemberRank(WorldSession* session, std::string const& name, bool demote) +void Guild::HandleUpdateMemberRank(WorldSession* session, uint64 guid, bool demote) { Player* player = session->GetPlayer(); GuildCommandType type = demote ? GUILD_COMMAND_DEMOTE : GUILD_COMMAND_PROMOTE; @@ -1643,8 +1928,9 @@ void Guild::HandleUpdateMemberRank(WorldSession* session, std::string const& nam if (!_HasRankRight(player, demote ? GR_RIGHT_DEMOTE : GR_RIGHT_PROMOTE)) SendCommandResult(session, type, ERR_GUILD_PERMISSIONS); // Promoted player must be a member of guild - else if (Member* member = GetMember(name)) + else if (Member* member = GetMember(guid)) { + std::string name = member->GetName(); // Player cannot promote himself if (member->IsSamePlayer(player->GetGUID())) { @@ -1687,6 +1973,36 @@ void Guild::HandleUpdateMemberRank(WorldSession* session, std::string const& nam } } +void Guild::HandleSetMemberRank(WorldSession* session, uint64 targetGuid, uint64 setterGuid, uint32 rank) +{ + Player* player = session->GetPlayer(); + Member* member = GetMember(targetGuid); + GuildRankRights rights = GR_RIGHT_PROMOTE; + GuildCommandType type = GUILD_COMMAND_PROMOTE; + + if (rank > member->GetRankId()) + { + rights = GR_RIGHT_DEMOTE; + type = GUILD_COMMAND_DEMOTE; + } + + // Promoted player must be a member of guild + if (!_HasRankRight(player, rights)) + { + SendCommandResult(session, type, ERR_GUILD_PERMISSIONS); + return; + } + + // Player cannot promote himself + if (member->IsSamePlayer(player->GetGUID())) + { + SendCommandResult(session, type, ERR_GUILD_NAME_INVALID); + return; + } + + SendGuildRanksUpdate(setterGuid, targetGuid, rank); +} + void Guild::HandleAddNewRank(WorldSession* session, std::string const& name) { uint8 size = _GetRanksSize(); @@ -1696,16 +2012,7 @@ void Guild::HandleAddNewRank(WorldSession* session, std::string const& name) // Only leader can add new rank if (_IsLeader(session->GetPlayer())) if (_CreateRank(name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK)) - { - char aux[2]; - sprintf(aux, "%u", size); - _BroadcastEvent(GE_RANK_UPDATED, 0, aux, name.c_str()); - } -} - -void Guild::HandleRemoveLowestRank(WorldSession* session) -{ - HandleRemoveRank(session, _GetLowestRankId()); + _BroadcastEvent(GE_RANK_CREATED, 0); } void Guild::HandleRemoveRank(WorldSession* session, uint8 rankId) @@ -1720,17 +2027,17 @@ void Guild::HandleRemoveRank(WorldSession* session, uint8 rankId) stmt->setUInt8(1, rankId); CharacterDatabase.Execute(stmt); // Delete rank - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_LOWEST_RANK); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANK); stmt->setUInt32(0, m_id); stmt->setUInt8(1, rankId); CharacterDatabase.Execute(stmt); - m_ranks.pop_back(); + m_ranks.erase(m_ranks.begin() + rankId); - _BroadcastEvent(GE_RANK_DELETED, 0); + _BroadcastEvent(GE_RANK_DELETED, rankId); } -void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount) +void Guild::HandleMemberDepositMoney(WorldSession* session, uint64 amount, bool cashFlow /*=false*/) { Player* player = session->GetPlayer(); @@ -1739,11 +2046,13 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount) SQLTransaction trans = CharacterDatabase.BeginTransaction(); _ModifyBankMoney(trans, amount, true); + if (!cashFlow) + { + player->ModifyMoney(-int64(amount)); + player->SaveGoldToDB(trans); + } - player->ModifyMoney(-int32(amount)); - player->SaveGoldToDB(trans); - _LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_MONEY, uint8(0), player->GetGUIDLow(), amount); - + _LogBankEvent(trans, cashFlow ? GUILD_BANK_LOG_CASH_FLOW_DEPOSIT : GUILD_BANK_LOG_DEPOSIT_MONEY, uint8(0), player->GetGUIDLow(), amount); CharacterDatabase.CommitTransaction(trans); std::string aux = ByteArrayToHexStr(reinterpret_cast<uint8*>(&m_bankMoney), 8, true); @@ -1752,15 +2061,15 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount) if (player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(player->GetSession()->GetAccountId(), - "GM %s (Account: %u) deposit money (Amount: %u) to guild bank (Guild ID %u)", + "GM %s (Account: %u) deposit money (Amount: " UI64FMTD ") to guild bank (Guild ID %u)", player->GetName().c_str(), player->GetSession()->GetAccountId(), amount, m_id); } } -bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair) +bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint64 amount, bool repair) { - //clamp amount to MAX_MONEY_AMOUNT, Players can't hold more than that anyway - amount = std::min(amount, MAX_MONEY_AMOUNT); + // clamp amount to MAX_MONEY_AMOUNT, Players can't hold more than that anyway + amount = std::min(amount, uint64(MAX_MONEY_AMOUNT)); if (m_bankMoney < amount) // Not enough money in bank return false; @@ -1771,7 +2080,7 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool if (!member) return false; - if (uint32(_GetMemberRemainingMoney(member)) < amount) // Check if we have enough slot/money today + if (uint64(_GetMemberRemainingMoney(member)) < amount) // Check if we have enough slot/money today return false; // Call script after validation and before money transfer. @@ -1811,6 +2120,8 @@ void Guild::HandleMemberLogout(WorldSession* session) member->ResetFlags(); } _BroadcastEvent(GE_SIGNED_OFF, player->GetGUID(), player->GetName().c_str()); + + SaveToDB(); } void Guild::HandleDisband(WorldSession* session) @@ -1824,50 +2135,104 @@ void Guild::HandleDisband(WorldSession* session) } } -// Send data to client -void Guild::SendInfo(WorldSession* session) const +void Guild::HandleGuildPartyRequest(WorldSession* session) { - WorldPacket data(SMSG_GUILD_INFO, m_name.size() + 4 + 4 + 4); - data << m_name; - data.AppendPackedTime(m_createdDate); // 3.x (prev. year + month + day) - data << uint32(m_members.size()); // Number of members - data << m_accountsNumber; // Number of accounts + Player* player = session->GetPlayer(); + Group* group = player->GetGroup(); + + // Make sure player is a member of the guild and that he is in a group. + if (!IsMember(player->GetGUID()) || !group) + return; + + WorldPacket data(SMSG_GUILD_PARTY_STATE_RESPONSE, 13); + data.WriteBit(player->GetMap()->GetOwnerGuildId(player->GetTeam()) == GetId()); // Is guild group + data.FlushBits(); + data << float(0.f); // Guild XP multiplier + data << uint32(0); // Current guild members + data << uint32(0); // Needed guild members session->SendPacket(&data); - TC_LOG_DEBUG("guild", "SMSG_GUILD_INFO [%s]", session->GetPlayerInfo().c_str()); + TC_LOG_DEBUG("guild", "SMSG_GUILD_PARTY_STATE_RESPONSE [%s]", session->GetPlayerInfo().c_str()); } void Guild::SendEventLog(WorldSession* session) const { - WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 1 + m_eventLog->GetSize() * (1 + 8 + 4)); + WorldPacket data(SMSG_GUILD_EVENT_LOG_QUERY_RESULT, 1 + m_eventLog->GetSize() * (1 + 8 + 4)); m_eventLog->WritePacket(data); session->SendPacket(&data); - TC_LOG_DEBUG("guild", "MSG_GUILD_EVENT_LOG_QUERY [%s]", session->GetPlayerInfo().c_str()); + TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT_LOG_QUERY_RESULT [%s]", session->GetPlayerInfo().c_str()); } -void Guild::SendBankLog(WorldSession* session, uint8 tabId) const +void Guild::SendNewsUpdate(WorldSession* session) { - // GUILD_BANK_MAX_TABS send by client for money log - if (tabId < _GetPurchasedTabsSize() || tabId == GUILD_BANK_MAX_TABS) + uint32 size = m_newsLog->GetSize(); + GuildLog* logs = m_newsLog->GetGuildLog(); + + if (!logs) + return; + + WorldPacket data(SMSG_GUILD_NEWS_UPDATE, (21 + size * (26 + 8)) / 8 + (8 + 6 * 4) * size); + data.WriteBits(size, 21); + + for (GuildLog::const_iterator itr = logs->begin(); itr != logs->end(); ++itr) { - const LogHolder* pLog = m_bankEventLog[tabId]; - WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, pLog->GetSize() * (4 * 4 + 1) + 1 + 1); - data << uint8(tabId); - pLog->WritePacket(data); - session->SendPacket(&data); - TC_LOG_DEBUG("guild", "MSG_GUILD_BANK_LOG_QUERY [%s]", session->GetPlayerInfo().c_str()); + data.WriteBits(0, 26); // Not yet implemented used for guild achievements + ObjectGuid guid = ((NewsLogEntry*)(*itr))->GetPlayerGuid(); + + data.WriteBit(guid[7]); + data.WriteBit(guid[0]); + data.WriteBit(guid[6]); + data.WriteBit(guid[5]); + data.WriteBit(guid[4]); + data.WriteBit(guid[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[2]); } -} -void Guild::SendBankTabData(WorldSession* session, uint8 tabId) const -{ - if (tabId < _GetPurchasedTabsSize()) - _SendBankContent(session, tabId); + data.FlushBits(); + + for (GuildLog::const_iterator itr = logs->begin(); itr != logs->end(); ++itr) + { + NewsLogEntry* news = (NewsLogEntry*)(*itr); + ObjectGuid guid = news->GetPlayerGuid(); + data.WriteByteSeq(guid[5]); + + data << uint32(news->GetFlags()); // 1 sticky + data << uint32(news->GetValue()); + data << uint32(0); + + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[6]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[1]); + + data << uint32(news->GetGUID()); + data << uint32(news->GetType()); + data.AppendPackedTime(news->GetTimestamp()); + } + + session->SendPacket(&data); + TC_LOG_DEBUG("guild", "SMSG_GUILD_NEWS_UPDATE [%s]", session->GetPlayerInfo().c_str()); } -void Guild::SendBankTabsInfo(WorldSession* session, bool sendAllSlots /*= false*/) const +void Guild::SendBankLog(WorldSession* session, uint8 tabId) const { - _SendBankList(session, 0, sendAllSlots); + // GUILD_BANK_MAX_TABS send by client for money log + if (tabId < _GetPurchasedTabsSize() || tabId == GUILD_BANK_MAX_TABS) + { + LogHolder const* log = m_bankEventLog[tabId]; + WorldPacket data(SMSG_GUILD_BANK_LOG_QUERY_RESULT, log->GetSize() * (4 * 4 + 1) + 1 + 1); + data.WriteBit(GetLevel() >= 5 && tabId == GUILD_BANK_MAX_TABS); // has Cash Flow perk + log->WritePacket(data); + data << uint32(tabId); + //if (tabId == GUILD_BANK_MAX_TABS && hasCashFlow) + // data << uint64(cashFlowContribution); + session->SendPacket(&data); + TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_LOG_QUERY_RESULT [%s] TabId: %u", session->GetPlayerInfo().c_str(), tabId); + } } void Guild::SendBankTabText(WorldSession* session, uint8 tabId) const @@ -1884,11 +2249,12 @@ void Guild::SendPermissions(WorldSession* session) const uint8 rankId = member->GetRankId(); - WorldPacket data(MSG_GUILD_PERMISSIONS, 4 * 15 + 1); + WorldPacket data(SMSG_GUILD_PERMISSIONS_QUERY_RESULTS, 4 * 15 + 1); data << uint32(rankId); + data << uint32(_GetPurchasedTabsSize()); data << uint32(_GetRankRights(rankId)); data << uint32(_GetMemberRemainingMoney(member)); - data << uint8(_GetPurchasedTabsSize()); + data.WriteBits(GUILD_BANK_MAX_TABS, 23); for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) { data << uint32(_GetRankBankTabRights(rankId, tabId)); @@ -1896,7 +2262,7 @@ void Guild::SendPermissions(WorldSession* session) const } session->SendPacket(&data); - TC_LOG_DEBUG("guild", "MSG_GUILD_PERMISSIONS [%s] Rank: %u", session->GetPlayerInfo().c_str(), rankId); + TC_LOG_DEBUG("guild", "SMSG_GUILD_PERMISSIONS_QUERY_RESULTS [%s] Rank: %u", session->GetPlayerInfo().c_str(), rankId); } void Guild::SendMoneyInfo(WorldSession* session) const @@ -1906,14 +2272,30 @@ void Guild::SendMoneyInfo(WorldSession* session) const return; int32 amount = _GetMemberRemainingMoney(member); - WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4); - data << int32(amount); + WorldPacket data(SMSG_GUILD_BANK_MONEY_WITHDRAWN, 8); + data << int64(amount); session->SendPacket(&data); - TC_LOG_DEBUG("guild", "MSG_GUILD_BANK_MONEY_WITHDRAWN [%s] Money: %u", session->GetPlayerInfo().c_str(), amount); + TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_MONEY_WITHDRAWN [%s] Money: %u", session->GetPlayerInfo().c_str(), amount); } void Guild::SendLoginInfo(WorldSession* session) { + Player* player = session->GetPlayer(); + Member* member = GetMember(player->GetGUID()); + if (!member) + return; + + /* + Login sequence: + SMSG_GUILD_EVENT - GE_MOTD + SMSG_GUILD_RANK + SMSG_GUILD_EVENT - GE_SIGNED_ON + -- learn perks + SMSG_GUILD_REPUTATION_WEEKLY_CAP + SMSG_GUILD_ACHIEVEMENT_DATA + SMSG_GUILD_MEMBER_DAILY_RESET // bank withdrawal reset + */ + WorldPacket data(SMSG_GUILD_EVENT, 1 + 1 + m_motd.size() + 1); data << uint8(GE_MOTD); data << uint8(1); @@ -1922,18 +2304,34 @@ void Guild::SendLoginInfo(WorldSession* session) TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT [%s] MOTD", session->GetPlayerInfo().c_str()); - SendBankTabsInfo(session); + SendGuildRankInfo(session); + _BroadcastEvent(GE_SIGNED_ON, player->GetGUID(), player->GetName().c_str()); - Player* player = session->GetPlayer(); + // Send to self separately, player is not in world yet and is not found by _BroadcastEvent + data.Initialize(SMSG_GUILD_EVENT, 1 + 1 + player->GetName().size() + 8); + data << uint8(GE_SIGNED_ON); + data << uint8(1); + data << player->GetName(); + data << uint64(player->GetGUID()); + session->SendPacket(&data); - HandleRoster(session); - _BroadcastEvent(GE_SIGNED_ON, player->GetGUID(), player->GetName().c_str()); + data.Initialize(SMSG_GUILD_MEMBER_DAILY_RESET, 0); // tells the client to request bank withdrawal limit + session->SendPacket(&data); - if (Member* member = GetMember(player->GetGUID())) - { - member->SetStats(player); - member->AddFlag(GUILDMEMBER_STATUS_ONLINE); - } + if (!sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED)) + return; + + for (uint32 i = 0; i < sGuildPerkSpellsStore.GetNumRows(); ++i) + if (GuildPerkSpellsEntry const* entry = sGuildPerkSpellsStore.LookupEntry(i)) + if (entry->Level <= GetLevel()) + player->LearnSpell(entry->SpellId, true); + + SendGuildReputationWeeklyCap(session, member->GetWeekReputation()); + + m_achievementMgr.SendAllAchievementData(player); + + member->SetStats(player); + member->AddFlag(GUILDMEMBER_STATUS_ONLINE); } // Loading methods @@ -1947,8 +2345,11 @@ bool Guild::LoadFromDB(Field* fields) m_motd = fields[9].GetString(); m_createdDate = time_t(fields[10].GetUInt32()); m_bankMoney = fields[11].GetUInt64(); + _level = fields[12].GetUInt32(); + _experience = fields[13].GetUInt64(); + _todayExperience = fields[14].GetUInt64(); - uint8 purchasedTabs = uint8(fields[12].GetUInt64()); + uint8 purchasedTabs = uint8(fields[15].GetUInt64()); if (purchasedTabs > GUILD_BANK_MAX_TABS) purchasedTabs = GUILD_BANK_MAX_TABS; @@ -2048,6 +2449,21 @@ bool Guild::LoadBankEventLogFromDB(Field* fields) return true; } +void Guild::LoadGuildNewsLogFromDB(Field* fields) +{ + if (!m_newsLog->CanInsert()) + return; + + m_newsLog->LoadEvent(new NewsLogEntry( + m_id, // guild id + fields[1].GetUInt32(), // guid + fields[6].GetUInt32(), // timestamp //64 bits? + GuildNews(fields[2].GetUInt8()), // type + fields[3].GetUInt32(), // player guid + fields[4].GetUInt32(), // Flags + fields[5].GetUInt32())); // value +} + void Guild::LoadBankTabFromDB(Field* fields) { uint8 tabId = fields[1].GetUInt8(); @@ -2076,7 +2492,7 @@ bool Guild::Validate() // GUILD RANKS represent a sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges). // The lower rank id is considered higher rank - so promotion does rank-- and demotion does rank++ // Between ranks in sequence cannot be gaps - so 0, 1, 2, 4 is impossible - // Min ranks count is 5 and max is 10. + // Min ranks count is 2 and max is 10. bool broken_ranks = false; uint8 ranks = _GetRanksSize(); if (ranks < GUILD_RANKS_MIN_COUNT || ranks > GUILD_RANKS_MAX_COUNT) @@ -2156,6 +2572,21 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin } } +void Guild::BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std::string const& msg, std::string const& prefix) const +{ + if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) + { + WorldPacket data; + ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, LANG_ADDON, session->GetPlayer(), NULL, msg, 0, "", DEFAULT_LOCALE, prefix); + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (Player* player = itr->second->FindPlayer()) + if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && + !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()) && + player->GetSession()->IsAddonRegistered(prefix)) + player->GetSession()->SendPacket(&data); + } +} + void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const { for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) @@ -2235,7 +2666,7 @@ bool Guild::AddMember(uint64 guid, uint8 rankId) player->SetInGuild(m_id); player->SetGuildIdInvited(0); player->SetRank(rankId); - member->SetStats(player); + player->SetGuildLevel(GetLevel()); SendLoginInfo(player->GetSession()); name = player->GetName(); } @@ -2256,10 +2687,12 @@ bool Guild::AddMember(uint64 guid, uint8 rankId) fields[1].GetUInt8(), fields[2].GetUInt8(), fields[3].GetUInt16(), - fields[4].GetUInt32()); + fields[4].GetUInt32(), + 0); ok = member->CheckStats(); } + if (!ok) { delete member; @@ -2274,6 +2707,7 @@ bool Guild::AddMember(uint64 guid, uint8 rankId) _UpdateAccountsNumber(); _LogEvent(GUILD_EVENT_LOG_JOIN_GUILD, lowguid); _BroadcastEvent(GE_JOINED, guid, name.c_str()); + sGuildFinderMgr->RemoveAllMembershipRequestsFromPlayer(lowguid); // Call scripts if member was succesfully added (and stored to database) sScriptMgr->OnGuildAddMember(this, player, rankId); @@ -2333,6 +2767,12 @@ void Guild::DeleteMember(uint64 guid, bool isDisbanding, bool isKicked, bool can { player->SetInGuild(0); player->SetRank(0); + player->SetGuildLevel(0); + + for (uint32 i = 0; i < sGuildPerkSpellsStore.GetNumRows(); ++i) + if (GuildPerkSpellsEntry const* entry = sGuildPerkSpellsStore.LookupEntry(i)) + if (entry->Level <= GetLevel()) + player->RemoveSpell(entry->SpellId, false, false); } _DeleteMemberFromDB(lowguid); @@ -2351,6 +2791,12 @@ bool Guild::ChangeMemberRank(uint64 guid, uint8 newRank) return false; } +bool Guild::IsMember(uint64 guid) const +{ + Members::const_iterator itr = m_members.find(GUID_LOPART(guid)); + return itr != m_members.end(); +} + // Bank (items move) void Guild::SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount) { @@ -2393,6 +2839,7 @@ void Guild::SetBankTabText(uint8 tabId, std::string const& text) void Guild::_CreateLogHolders() { m_eventLog = new LogHolder(sWorld->getIntConfig(CONFIG_GUILD_EVENT_LOG_COUNT)); + m_newsLog = new LogHolder(sWorld->getIntConfig(CONFIG_GUILD_NEWS_LOG_COUNT)); for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId) m_bankEventLog[tabId] = new LogHolder(sWorld->getIntConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT)); } @@ -2783,20 +3230,6 @@ bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError return true; } -void Guild::_SendBankContent(WorldSession* session, uint8 tabId) const -{ - uint64 guid = session->GetPlayer()->GetGUID(); - if (!_MemberHasTabRights(guid, tabId, GUILD_BANK_RIGHT_VIEW_TAB)) - return; - - _SendBankList(session, tabId, true); -} - -void Guild::_SendBankMoneyUpdate(WorldSession* session) const -{ - _SendBankList(session); -} - void Guild::_SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) const { ASSERT(pSrc->IsBank() || pDest->IsBank()); @@ -2831,7 +3264,68 @@ void Guild::_SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) cons void Guild::_SendBankContentUpdate(uint8 tabId, SlotIds slots) const { - _SendBankList(NULL, tabId, false, &slots); + if (BankTab const* tab = GetBankTab(tabId)) + { + ByteBuffer tabData; + WorldPacket data(SMSG_GUILD_BANK_LIST, 1200); + data.WriteBit(0); + data.WriteBits(slots.size(), 20); // Item count + data.WriteBits(0, 22); // Tab count + + for (SlotIds::const_iterator itr = slots.begin(); itr != slots.end(); ++itr) + { + data.WriteBit(0); + + Item const* tabItem = tab->GetItem(*itr); + uint32 enchantCount = 0; + if (tabItem) + { + for (uint32 enchSlot = 0; enchSlot < MAX_ENCHANTMENT_SLOT; ++enchSlot) + { + if (uint32 enchantId = tabItem->GetEnchantmentId(EnchantmentSlot(enchSlot))) + { + tabData << uint32(enchantId); + tabData << uint32(enchSlot); + ++enchantCount; + } + } + } + + data.WriteBits(enchantCount, 23); // enchantment count + + tabData << uint32(0); + tabData << uint32(0); + tabData << uint32(0); + tabData << uint32(tabItem ? tabItem->GetCount() : 0); // ITEM_FIELD_STACK_COUNT + tabData << uint32(*itr); + tabData << uint32(0); + tabData << uint32(tabItem ? tabItem->GetEntry() : 0); + tabData << uint32(tabItem ? tabItem->GetItemRandomPropertyId() : 0); + tabData << uint32(tabItem ? abs(tabItem->GetSpellCharges()) : 0); // Spell charges + tabData << uint32(tabItem ? tabItem->GetItemSuffixFactor() : 0); // SuffixFactor + } + + data.FlushBits(); + + data << uint64(m_bankMoney); + if (!tabData.empty()) + data.append(tabData); + + data << uint32(tabId); + + size_t rempos = data.wpos(); + data << uint32(0); // Item withdraw amount, will be filled later + + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (_MemberHasTabRights(itr->second->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (Player* player = itr->second->FindPlayer()) + { + data.put<uint32>(rempos, uint32(_GetMemberRemainingSlots(itr->second, tabId))); + player->GetSession()->SendPacket(&data); + } + + TC_LOG_DEBUG("guild", "WORLD: Sent (SMSG_GUILD_BANK_LIST)"); + } } void Guild::_BroadcastEvent(GuildEvents guildEvent, uint64 guid, const char* param1, const char* param2, const char* param3) const @@ -2858,69 +3352,293 @@ void Guild::_BroadcastEvent(GuildEvents guildEvent, uint64 guid, const char* par TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT [Broadcast] Event: %s (%u)", _GetGuildEventString(guildEvent).c_str(), guildEvent); } -void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/, bool sendAllSlots /*= false*/, SlotIds *slots /*= NULL*/) const +void Guild::SendBankList(WorldSession* session, uint8 tabId, bool withContent, bool withTabInfo) const { + Member const* member = GetMember(session->GetPlayer()->GetGUID()); + if (!member) // Shouldn't happen, just in case + return; + + ByteBuffer tabData; WorldPacket data(SMSG_GUILD_BANK_LIST, 500); - data << uint64(m_bankMoney); - data << uint8(tabId); - size_t rempos = data.wpos(); - data << uint32(0); - data << uint8(sendAllSlots); + data.WriteBit(0); + uint32 itemCount = 0; + if (withContent && _MemberHasTabRights(session->GetPlayer()->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (BankTab const* tab = GetBankTab(tabId)) + for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) + if (tab->GetItem(slotId)) + ++itemCount; + + data.WriteBits(itemCount, 20); + data.WriteBits(withTabInfo ? _GetPurchasedTabsSize() : 0, 22); + if (withContent && _MemberHasTabRights(session->GetPlayer()->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + { + if (BankTab const* tab = GetBankTab(tabId)) + { + for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) + { + if (Item* tabItem = tab->GetItem(slotId)) + { + data.WriteBit(0); + + uint32 enchants = 0; + for (uint32 ench = 0; ench < MAX_ENCHANTMENT_SLOT; ++ench) + { + if (uint32 enchantId = tabItem->GetEnchantmentId(EnchantmentSlot(ench))) + { + tabData << uint32(enchantId); + tabData << uint32(ench); + ++enchants; + } + } + + data.WriteBits(enchants, 23); + + tabData << uint32(0); + tabData << uint32(0); + tabData << uint32(0); + tabData << uint32(tabItem->GetCount()); // ITEM_FIELD_STACK_COUNT + tabData << uint32(slotId); + tabData << uint32(0); + tabData << uint32(tabItem->GetEntry()); + tabData << uint32(tabItem->GetItemRandomPropertyId()); + tabData << uint32(abs(tabItem->GetSpellCharges())); // Spell charges + tabData << uint32(tabItem->GetItemSuffixFactor()); // SuffixFactor + } + } + } + } - if (sendAllSlots && !tabId) + if (withTabInfo) { - data << uint8(_GetPurchasedTabsSize()); // Number of tabs for (uint8 i = 0; i < _GetPurchasedTabsSize(); ++i) - m_bankTabs[i]->WriteInfoPacket(data); + { + data.WriteBits(m_bankTabs[i]->GetIcon().length(), 9); + data.WriteBits(m_bankTabs[i]->GetName().length(), 7); + } } - BankTab const* tab = GetBankTab(tabId); - if (!tab) - data << uint8(0); - else if (sendAllSlots) - tab->WritePacket(data); - else if (slots && !slots->empty()) + data.FlushBits(); + + if (withTabInfo) { - data << uint8(slots->size()); - for (SlotIds::const_iterator itr = slots->begin(); itr != slots->end(); ++itr) - tab->WriteSlotPacket(data, *itr, false); + for (uint8 i = 0; i < _GetPurchasedTabsSize(); ++i) + { + data.WriteString(m_bankTabs[i]->GetIcon()); + data << uint32(i); + data.WriteString(m_bankTabs[i]->GetName()); + } } - else - data << uint8(0); - if (session) + data << uint64(m_bankMoney); + if (!tabData.empty()) + data.append(tabData); + + data << uint32(tabId); + data << uint32(_GetMemberRemainingSlots(member, tabId)); + + session->SendPacket(&data); + + TC_LOG_DEBUG("guild", "WORLD: Sent (SMSG_GUILD_BANK_LIST)"); +} + +void Guild::SendGuildRanksUpdate(uint64 setterGuid, uint64 targetGuid, uint32 rank) +{ + ObjectGuid tarGuid = targetGuid; + ObjectGuid setGuid = setterGuid; + + Member* member = GetMember(targetGuid); + ASSERT(member); + + WorldPacket data(SMSG_GUILD_RANKS_UPDATE, 100); + data.WriteBit(setGuid[7]); + data.WriteBit(setGuid[2]); + data.WriteBit(tarGuid[2]); + data.WriteBit(setGuid[1]); + data.WriteBit(tarGuid[1]); + data.WriteBit(tarGuid[7]); + data.WriteBit(tarGuid[0]); + data.WriteBit(tarGuid[5]); + data.WriteBit(tarGuid[4]); + data.WriteBit(rank < member->GetRankId()); // 1 == higher, 0 = lower? + data.WriteBit(setGuid[5]); + data.WriteBit(setGuid[0]); + data.WriteBit(tarGuid[6]); + data.WriteBit(setGuid[3]); + data.WriteBit(setGuid[6]); + data.WriteBit(tarGuid[3]); + data.WriteBit(setGuid[4]); + + data.FlushBits(); + + data << uint32(rank); + data.WriteByteSeq(setGuid[3]); + data.WriteByteSeq(tarGuid[7]); + data.WriteByteSeq(setGuid[6]); + data.WriteByteSeq(setGuid[2]); + data.WriteByteSeq(tarGuid[5]); + data.WriteByteSeq(tarGuid[0]); + data.WriteByteSeq(setGuid[7]); + data.WriteByteSeq(setGuid[5]); + data.WriteByteSeq(tarGuid[2]); + data.WriteByteSeq(tarGuid[1]); + data.WriteByteSeq(setGuid[0]); + data.WriteByteSeq(setGuid[4]); + data.WriteByteSeq(setGuid[1]); + data.WriteByteSeq(tarGuid[3]); + data.WriteByteSeq(tarGuid[6]); + data.WriteByteSeq(tarGuid[4]); + BroadcastPacket(&data); + + member->ChangeRank(rank); + + TC_LOG_DEBUG("network", "SMSG_GUILD_RANKS_UPDATE [Broadcast] Target: %u, Issuer: %u, RankId: %u", + GUID_LOPART(targetGuid), GUID_LOPART(setterGuid), rank); +} + +void Guild::GiveXP(uint32 xp, Player* source) +{ + if (!sWorld->getBoolConfig(CONFIG_GUILD_LEVELING_ENABLED)) + return; + + /// @todo: Award reputation and count activity for player + + if (GetLevel() >= sWorld->getIntConfig(CONFIG_GUILD_MAX_LEVEL)) + xp = 0; // SMSG_GUILD_XP_GAIN is always sent, even for no gains + + if (GetLevel() < GUILD_EXPERIENCE_UNCAPPED_LEVEL) + xp = std::min(xp, sWorld->getIntConfig(CONFIG_GUILD_DAILY_XP_CAP) - uint32(_todayExperience)); + + WorldPacket data(SMSG_GUILD_XP_GAIN, 8); + data << uint64(xp); + source->GetSession()->SendPacket(&data); + + _experience += xp; + _todayExperience += xp; + + if (!xp) + return; + + uint32 oldLevel = GetLevel(); + + // Ding, mon! + while (GetExperience() >= sGuildMgr->GetXPForGuildLevel(GetLevel()) && GetLevel() < sWorld->getIntConfig(CONFIG_GUILD_MAX_LEVEL)) { - int32 numSlots = 0; - if (Member const* member = GetMember(session->GetPlayer()->GetGUID())) - numSlots = _GetMemberRemainingSlots(member, tabId); - data.put<uint32>(rempos, numSlots); - session->SendPacket(&data); - TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_LIST [%s]: TabId: %u, FullSlots: %u, slots: %d", - session->GetPlayerInfo().c_str(), tabId, sendAllSlots, numSlots); + _experience -= sGuildMgr->GetXPForGuildLevel(GetLevel()); + ++_level; + + // Find all guild perks to learn + std::vector<uint32> perksToLearn; + for (uint32 i = 0; i < sGuildPerkSpellsStore.GetNumRows(); ++i) + if (GuildPerkSpellsEntry const* entry = sGuildPerkSpellsStore.LookupEntry(i)) + if (entry->Level > oldLevel && entry->Level <= GetLevel()) + perksToLearn.push_back(entry->SpellId); + + // Notify all online players that guild level changed and learn perks + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + { + if (Player* player = itr->second->FindPlayer()) + { + player->SetGuildLevel(GetLevel()); + for (size_t i = 0; i < perksToLearn.size(); ++i) + player->LearnSpell(perksToLearn[i], true); + } + } + + AddGuildNews(GUILD_NEWS_LEVEL_UP, 0, 0, _level); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL, GetLevel(), 0, 0, NULL, source); + + ++oldLevel; } - else /// @todo - Probably this is just sent to session + those that have sent CMSG_GUILD_BANKER_ACTIVATE +} + +void Guild::SendGuildXP(WorldSession* session /* = NULL */) const +{ + //Member const* member = GetMember(session->GetGuidLow()); + + WorldPacket data(SMSG_GUILD_XP, 40); + data << uint64(/*member ? member->GetTotalActivity() :*/ 0); + data << uint64(sGuildMgr->GetXPForGuildLevel(GetLevel()) - GetExperience()); // XP missing for next level + data << uint64(GetTodayExperience()); + data << uint64(/*member ? member->GetWeeklyActivity() :*/ 0); + data << uint64(GetExperience()); + session->SendPacket(&data); +} + +void Guild::SendGuildReputationWeeklyCap(WorldSession* session, uint32 reputation) const +{ + uint32 cap = sWorld->getIntConfig(CONFIG_GUILD_WEEKLY_REP_CAP) - reputation; + WorldPacket data(SMSG_GUILD_REPUTATION_WEEKLY_CAP, 4); + data << uint32(cap); + session->SendPacket(&data); + TC_LOG_DEBUG("guild", "SMSG_GUILD_REPUTATION_WEEKLY_CAP [%s]: Left: %u", + session->GetPlayerInfo().c_str(), cap); +} + +void Guild::ResetTimes(bool weekly) +{ + _todayExperience = 0; + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + itr->second->ResetValues(weekly); + if (Player* player = itr->second->FindPlayer()) { - if (!_MemberHasTabRights(itr->second->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) - continue; - Player* player = itr->second->FindPlayer(); - if (!player) - continue; - - uint32 numSlots = _GetMemberRemainingSlots(itr->second, tabId); - data.put<uint32>(rempos, numSlots); + //SendGuildXP(player->GetSession()); + WorldPacket data(SMSG_GUILD_MEMBER_DAILY_RESET, 0); // tells the client to request bank withdrawal limit player->GetSession()->SendPacket(&data); - TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_LIST [%s]: TabId: %u, FullSlots: %u, slots: %u" - , player->GetName().c_str(), tabId, sendAllSlots, numSlots); } } } -void Guild::ResetTimes() +void Guild::AddGuildNews(uint8 type, uint64 guid, uint32 flags, uint32 value) { - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) - itr->second->ResetValues(); + uint32 lowGuid = GUID_LOPART(guid); + NewsLogEntry* news = new NewsLogEntry(m_id, m_newsLog->GetNextGUID(), GuildNews(type), lowGuid, flags, value); - _BroadcastEvent(GE_BANK_TAB_AND_MONEY_UPDATED, 0); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + m_newsLog->AddEvent(trans, news); + CharacterDatabase.CommitTransaction(trans); + + WorldPacket data(SMSG_GUILD_NEWS_UPDATE, 7 + 32); + data.WriteBits(1, 21); // size, we are only sending 1 news here + ByteBuffer buffer; + news->WritePacket(data, buffer); + + BroadcastPacket(&data); +} + +bool Guild::HasAchieved(uint32 achievementId) const +{ + return m_achievementMgr.HasAchieved(achievementId); +} + +void Guild::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player) +{ + m_achievementMgr.UpdateAchievementCriteria(type, miscValue1, miscValue2, miscValue3, unit, player); +} + +void Guild::HandleNewsSetSticky(WorldSession* session, uint32 newsId, bool sticky) +{ + GuildLog* logs = m_newsLog->GetGuildLog(); + GuildLog::iterator itr = logs->begin(); + while (itr != logs->end() && (*itr)->GetGUID() != newsId) + ++itr; + + if (itr == logs->end()) + { + TC_LOG_DEBUG("guild", "HandleNewsSetSticky: [%s] requested unknown newsId %u - Sticky: %u", + session->GetPlayerInfo().c_str(), newsId, sticky); + return; + } + + NewsLogEntry* news = (NewsLogEntry*)(*itr); + news->SetSticky(sticky); + + TC_LOG_DEBUG("guild", "HandleNewsSetSticky: [%s] chenged newsId %u sticky to %u", + session->GetPlayerInfo().c_str(), newsId, sticky); + + WorldPacket data(SMSG_GUILD_NEWS_UPDATE, 7 + 32); + data.WriteBits(1, 21); + ByteBuffer buffer; + news->WritePacket(data, buffer); + session->SendPacket(&data); } diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index ea0b2e44c53..d62907ddde5 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -19,31 +19,35 @@ #ifndef TRINITYCORE_GUILD_H #define TRINITYCORE_GUILD_H +#include "AchievementMgr.h" #include "World.h" #include "Item.h" #include "WorldPacket.h" #include "ObjectMgr.h" #include "Player.h" +#include "DBCStore.h" class Item; enum GuildMisc { - GUILD_BANK_MAX_TABS = 6, // send by client for money log also + GUILD_BANK_MAX_TABS = 8, // send by client for money log also GUILD_BANK_MAX_SLOTS = 98, GUILD_BANK_MONEY_LOGS_TAB = 100, // used for money log in DB - GUILD_RANKS_MIN_COUNT = 5, + GUILD_RANKS_MIN_COUNT = 2, GUILD_RANKS_MAX_COUNT = 10, GUILD_RANK_NONE = 0xFF, GUILD_WITHDRAW_MONEY_UNLIMITED = 0xFFFFFFFF, GUILD_WITHDRAW_SLOT_UNLIMITED = 0xFFFFFFFF, GUILD_EVENT_LOG_GUID_UNDEFINED = 0xFFFFFFFF, + GUILD_EXPERIENCE_UNCAPPED_LEVEL = 20, ///> Hardcoded in client, starting from this level, guild daily experience gain is unlimited. TAB_UNDEFINED = 0xFF, }; enum GuildMemberData { GUILD_MEMBER_DATA_ZONEID, + GUILD_MEMBER_DATA_ACHIEVEMENT_POINTS, GUILD_MEMBER_DATA_LEVEL, }; @@ -79,7 +83,7 @@ enum GuildRankRights GR_RIGHT_WITHDRAW_REPAIR = 0x00040000, // withdraw for repair GR_RIGHT_WITHDRAW_GOLD = 0x00080000, // withdraw gold GR_RIGHT_CREATE_GUILD_EVENT = 0x00100000, // wotlk - GR_RIGHT_ALL = 0x001DF1FF + GR_RIGHT_ALL = 0x00DDFFBF }; enum GuildCommandType @@ -128,37 +132,53 @@ enum GuildCommandError ERR_GUILD_NOT_ENOUGH_MONEY = 26, ERR_GUILD_BANK_FULL = 28, ERR_GUILD_ITEM_NOT_FOUND = 29, + ERR_GUILD_TOO_MUCH_MONEY = 31, + ERR_GUILD_BANK_WRONG_TAB = 32, + ERR_RANK_REQUIRES_AUTHENTICATOR = 34, + ERR_GUILD_BANK_VOUCHER_FAILED = 35, + ERR_GUILD_TRIAL_ACCOUNT = 36, + ERR_GUILD_UNDELETABLE_DUE_TO_LEVEL = 37, + ERR_GUILD_MOVE_STARTING = 38, + ERR_GUILD_REP_TOO_LOW = 39 }; enum GuildEvents { - GE_PROMOTION = 0, - GE_DEMOTION = 1, - GE_MOTD = 2, - GE_JOINED = 3, - GE_LEFT = 4, - GE_REMOVED = 5, - GE_LEADER_IS = 6, - GE_LEADER_CHANGED = 7, - GE_DISBANDED = 8, - GE_TABARDCHANGE = 9, - GE_RANK_UPDATED = 10, - GE_RANK_DELETED = 11, - GE_SIGNED_ON = 12, - GE_SIGNED_OFF = 13, - GE_GUILDBANKBAGSLOTS_CHANGED = 14, /// TODO: Sent when items are moved in gbank - all players with bank open will send tab query - GE_BANK_TAB_PURCHASED = 15, - GE_BANK_TAB_UPDATED = 16, - GE_BANK_MONEY_SET = 17, - GE_BANK_TAB_AND_MONEY_UPDATED = 18, - GE_BANK_TEXT_CHANGED = 19, + GE_PROMOTION = 1, + GE_DEMOTION = 2, + GE_MOTD = 3, + GE_JOINED = 4, + GE_LEFT = 5, + GE_REMOVED = 6, + GE_LEADER_IS = 7, + GE_LEADER_CHANGED = 8, + GE_DISBANDED = 9, + GE_TABARDCHANGE = 10, + GE_RANK_UPDATED = 11, + GE_RANK_CREATED = 12, + GE_RANK_DELETED = 13, + GE_RANK_ORDER_CHANGED = 14, + GE_FOUNDER = 15, + GE_SIGNED_ON = 16, + GE_SIGNED_OFF = 17, + GE_GUILDBANKBAGSLOTS_CHANGED = 18, + GE_BANK_TAB_PURCHASED = 19, + GE_BANK_TAB_UPDATED = 20, + GE_BANK_MONEY_SET = 21, + GE_BANK_TAB_AND_MONEY_UPDATED = 22, + GE_BANK_TEXT_CHANGED = 23, + // 24 - error 795 + GE_SIGNED_ON_MOBILE = 25, + GE_SIGNED_Off_MOBILE = 26, }; enum PetitionTurns { PETITION_TURN_OK = 0, PETITION_TURN_ALREADY_IN_GUILD = 2, - PETITION_TURN_NEED_MORE_SIGNATURES = 4 + PETITION_TURN_NEED_MORE_SIGNATURES = 4, + PETITION_TURN_GUILD_PERMISSIONS = 11, + PETITION_TURN_GUILD_NAME_INVALID = 12 }; enum PetitionSigns @@ -167,7 +187,10 @@ enum PetitionSigns PETITION_SIGN_ALREADY_SIGNED = 1, PETITION_SIGN_ALREADY_IN_GUILD = 2, PETITION_SIGN_CANT_SIGN_OWN = 3, - PETITION_SIGN_NOT_SERVER = 4 + PETITION_SIGN_NOT_SERVER = 4, + PETITION_SIGN_FULL = 5, + PETITION_SIGN_ALREADY_SIGNED_OTHER = 6, + PETITION_SIGN_RESTRICTED_ACCOUNT = 7 }; enum GuildBankRights @@ -190,7 +213,8 @@ enum GuildBankEventLogTypes GUILD_BANK_LOG_REPAIR_MONEY = 6, GUILD_BANK_LOG_MOVE_ITEM2 = 7, GUILD_BANK_LOG_UNK1 = 8, - GUILD_BANK_LOG_BUY_SLOT = 9 + GUILD_BANK_LOG_BUY_SLOT = 9, + GUILD_BANK_LOG_CASH_FLOW_DEPOSIT = 10 }; enum GuildEventLogTypes @@ -222,6 +246,28 @@ enum GuildMemberFlags GUILDMEMBER_STATUS_MOBILE = 0x0008, // remote chat from mobile app }; +enum GuildNews +{ + GUILD_NEWS_GUILD_ACHIEVEMENT = 0, + GUILD_NEWS_PLAYER_ACHIEVEMENT = 1, + GUILD_NEWS_DUNGEON_ENCOUNTER = 2, // @todo Implement + GUILD_NEWS_ITEM_LOOTED = 3, + GUILD_NEWS_ITEM_CRAFTED = 4, + GUILD_NEWS_ITEM_PURCHASED = 5, + GUILD_NEWS_LEVEL_UP = 6, +}; + +struct GuildReward +{ + uint32 Entry; + int32 Racemask; + uint64 Price; + uint32 AchievementId; + uint8 Standing; +}; + +uint32 const MinNewsItemLevel[MAX_CONTENT] = { 61, 90, 200, 353 }; + // Emblem info class EmblemInfo { @@ -295,19 +341,27 @@ private: m_flags(GUILDMEMBER_STATUS_NONE), m_logoutTime(::time(NULL)), m_accountId(0), - m_rankId(rankId) + m_rankId(rankId), + m_achievementPoints(0), + m_totalActivity(0), + m_weekActivity(0), + m_totalReputation(0), + m_weekReputation(0) { memset(m_bankWithdraw, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(int32)); } void SetStats(Player* player); - void SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId); + void SetStats(std::string const& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId, uint32 reputation); bool CheckStats() const; void SetPublicNote(std::string const& publicNote); void SetOfficerNote(std::string const& officerNote); - void SetZoneID(uint32 id) { m_zoneId = id; } + void SetZoneId(uint32 id) { m_zoneId = id; } + void SetAchievementPoints(uint32 val) { m_achievementPoints = val; } void SetLevel(uint8 var) { m_level = var; } + void AddReputation(uint32& reputation); + void AddActivity(uint64 activity); void AddFlag(uint8 var) { m_flags |= var; } void RemFlag(uint8 var) { m_flags &= ~var; } @@ -315,7 +369,6 @@ private: bool LoadFromDB(Field* fields); void SaveToDB(SQLTransaction& trans) const; - void WritePacket(WorldPacket& data, bool sendOfficerNote) const; uint64 GetGUID() const { return m_guid; } std::string const& GetName() const { return m_name; } @@ -328,6 +381,12 @@ private: uint8 GetLevel() const { return m_level; } uint8 GetFlags() const { return m_flags; } uint32 GetZoneId() const { return m_zoneId; } + uint32 GetAchievementPoints() const { return m_achievementPoints; } + uint64 GetTotalActivity() const { return m_totalActivity; } + uint64 GetWeekActivity() const { return m_weekActivity; } + uint32 GetTotalReputation() const { return m_totalReputation; } + uint32 GetWeekReputation() const { return m_weekReputation; } + bool IsOnline() { return (m_flags & GUILDMEMBER_STATUS_ONLINE); } void ChangeRank(uint8 newRank); @@ -339,7 +398,7 @@ private: void UpdateBankWithdrawValue(SQLTransaction& trans, uint8 tabId, uint32 amount); int32 GetBankWithdrawValue(uint8 tabId) const; - void ResetValues(); + void ResetValues(bool weekly = false); inline Player* FindPlayer() const { return ObjectAccessor::FindPlayer(m_guid); } @@ -360,6 +419,11 @@ private: std::string m_officerNote; int32 m_bankWithdraw[GUILD_BANK_MAX_TABS + 1]; + uint32 m_achievementPoints; + uint64 m_totalActivity; + uint64 m_weekActivity; + uint32 m_totalReputation; + uint32 m_weekReputation; }; // Base class for event entries @@ -374,7 +438,7 @@ private: uint64 GetTimestamp() const { return m_timestamp; } virtual void SaveToDB(SQLTransaction& trans) const = 0; - virtual void WritePacket(WorldPacket& data) const = 0; + virtual void WritePacket(WorldPacket& data, ByteBuffer& content) const = 0; protected: uint32 m_guildId; @@ -395,7 +459,7 @@ private: ~EventLogEntry() { } void SaveToDB(SQLTransaction& trans) const; - void WritePacket(WorldPacket& data) const; + void WritePacket(WorldPacket& data, ByteBuffer& content) const; private: GuildEventLogTypes m_eventType; @@ -413,31 +477,71 @@ private: return eventType == GUILD_BANK_LOG_DEPOSIT_MONEY || eventType == GUILD_BANK_LOG_WITHDRAW_MONEY || - eventType == GUILD_BANK_LOG_REPAIR_MONEY; + eventType == GUILD_BANK_LOG_REPAIR_MONEY || + eventType == GUILD_BANK_LOG_CASH_FLOW_DEPOSIT; } - BankEventLogEntry(uint32 guildId, uint32 guid, GuildBankEventLogTypes eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : + bool IsMoneyEvent() const + { + return IsMoneyEvent(m_eventType); + } + + BankEventLogEntry(uint32 guildId, uint32 guid, GuildBankEventLogTypes eventType, uint8 tabId, uint32 playerGuid, uint64 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : LogEntry(guildId, guid), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid), m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { } - BankEventLogEntry(uint32 guildId, uint32 guid, time_t timestamp, uint8 tabId, GuildBankEventLogTypes eventType, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : + BankEventLogEntry(uint32 guildId, uint32 guid, time_t timestamp, uint8 tabId, GuildBankEventLogTypes eventType, uint32 playerGuid, uint64 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid), m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { } ~BankEventLogEntry() { } void SaveToDB(SQLTransaction& trans) const; - void WritePacket(WorldPacket& data) const; + void WritePacket(WorldPacket& data, ByteBuffer& content) const; private: GuildBankEventLogTypes m_eventType; uint8 m_bankTabId; uint32 m_playerGuid; - uint32 m_itemOrMoney; + uint64 m_itemOrMoney; uint16 m_itemStackCount; uint8 m_destTabId; }; + // News log entry + class NewsLogEntry : public LogEntry + { + public: + NewsLogEntry(uint32 guildId, uint32 guid, GuildNews type, uint32 playerGuid, uint32 flags, uint32 value) : + LogEntry(guildId, guid), m_type(type), m_playerGuid(playerGuid), m_flags(flags), m_value(value) { } + + NewsLogEntry(uint32 guildId, uint32 guid, time_t timestamp, GuildNews type, uint32 playerGuid, uint32 flags, uint32 value) : + LogEntry(guildId, guid, timestamp), m_type(type), m_playerGuid(playerGuid), m_flags(flags), m_value(value) { } + + ~NewsLogEntry() { } + + GuildNews GetType() const { return m_type; } + uint64 GetPlayerGuid() const { return m_playerGuid ? MAKE_NEW_GUID(m_playerGuid, 0, HIGHGUID_PLAYER) : 0; } + uint32 GetValue() const { return m_value; } + uint32 GetFlags() const { return m_flags; } + void SetSticky(bool sticky) + { + if (sticky) + m_flags |= 1; + else + m_flags &= ~1; + } + + void SaveToDB(SQLTransaction& trans) const; + void WritePacket(WorldPacket& data, ByteBuffer& content) const; + + private: + GuildNews m_type; + uint32 m_playerGuid; + uint32 m_flags; + uint32 m_value; + }; + // Class encapsulating work with events collection typedef std::list<LogEntry*> GuildLog; @@ -457,6 +561,7 @@ private: // Writes information about all events to packet void WritePacket(WorldPacket& data) const; uint32 GetNextGUID(); + GuildLog* GetGuildLog() { return &m_log; } // Hack needed for news as WritePacket can't be used private: GuildLog m_log; @@ -476,7 +581,6 @@ private: void LoadFromDB(Field* fields); void SaveToDB(SQLTransaction& trans) const; - void WritePacket(WorldPacket& data) const; uint8 GetId() const { return m_rankId; } @@ -505,7 +609,6 @@ private: private: uint32 m_guildId; - uint8 m_rankId; std::string m_name; uint32 m_rights; @@ -535,10 +638,14 @@ private: void SetInfo(std::string const& name, std::string const& icon); void SetText(std::string const& text); - void SendText(const Guild* guild, WorldSession* session) const; + void SendText(Guild const* guild, WorldSession* session) const; + + std::string const& GetName() const { return m_name; } + std::string const& GetIcon() const { return m_icon; } + std::string const& GetText() const { return m_text; } inline Item* GetItem(uint8 slotId) const { return slotId < GUILD_BANK_MAX_SLOTS ? m_items[slotId] : NULL; } - bool SetItem(SQLTransaction& trans, uint8 slotId, Item* pItem); + bool SetItem(SQLTransaction& trans, uint8 slotId, Item* item); private: uint32 m_guildId; @@ -651,8 +758,11 @@ public: bool Create(Player* pLeader, std::string const& name); void Disband(); + void SaveToDB(); + // Getters uint32 GetId() const { return m_id; } + uint64 GetGUID() const { return MAKE_NEW_GUID(m_id, 0, HIGHGUID_GUILD); } uint64 GetLeaderGUID() const { return m_leaderGuid; } std::string const& GetName() const { return m_name; } std::string const& GetMOTD() const { return m_motd; } @@ -666,40 +776,44 @@ public: void HandleSetMOTD(WorldSession* session, std::string const& motd); void HandleSetInfo(WorldSession* session, std::string const& info); void HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo); - void HandleSetLeader(WorldSession* session, std::string const& name); + void HandleSetNewGuildMaster(WorldSession* session, std::string const& name); void HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string const& name, std::string const& icon); - void HandleSetMemberNote(WorldSession* session, std::string const& name, std::string const& note, bool officer); - void HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string const& name, uint32 rights, uint32 moneyPerDay, const GuildBankRightsAndSlotsVec& rightsAndSlots); + void HandleSetMemberNote(WorldSession* session, std::string const& note, uint64 guid, bool isPublic); + void HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string const& name, uint32 rights, uint32 moneyPerDay, GuildBankRightsAndSlotsVec const& rightsAndSlots); void HandleBuyBankTab(WorldSession* session, uint8 tabId); void HandleInviteMember(WorldSession* session, std::string const& name); void HandleAcceptMember(WorldSession* session); void HandleLeaveMember(WorldSession* session); - void HandleRemoveMember(WorldSession* session, std::string const& name); - void HandleUpdateMemberRank(WorldSession* session, std::string const& name, bool demote); + void HandleRemoveMember(WorldSession* session, uint64 guid); + void HandleUpdateMemberRank(WorldSession* session, uint64 guid, bool demote); + void HandleSetMemberRank(WorldSession* session, uint64 guid, uint64 setterGuid, uint32 rank); void HandleAddNewRank(WorldSession* session, std::string const& name); void HandleRemoveRank(WorldSession* session, uint8 rankId); - void HandleRemoveLowestRank(WorldSession* session); - void HandleMemberDepositMoney(WorldSession* session, uint32 amount); - bool HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair = false); + void HandleMemberDepositMoney(WorldSession* session, uint64 amount, bool cashFlow = false); + bool HandleMemberWithdrawMoney(WorldSession* session, uint64 amount, bool repair = false); void HandleMemberLogout(WorldSession* session); void HandleDisband(WorldSession* session); + void HandleGuildPartyRequest(WorldSession* session); + void HandleNewsSetSticky(WorldSession* session, uint32 newsId, bool sticky); void UpdateMemberData(Player* player, uint8 dataid, uint32 value); void OnPlayerStatusChange(Player* player, uint32 flag, bool state); // Send info to client - void SendInfo(WorldSession* session) const; + void SendGuildRankInfo(WorldSession* session) const; void SendEventLog(WorldSession* session) const; void SendBankLog(WorldSession* session, uint8 tabId) const; - void SendBankTabsInfo(WorldSession* session, bool showTabs = false) const; - void SendBankTabData(WorldSession* session, uint8 tabId) const; + void SendBankList(WorldSession* session, uint8 tabId, bool withContent, bool withTabInfo) const; + void SendGuildXP(WorldSession* session = NULL) const; void SendBankTabText(WorldSession* session, uint8 tabId) const; void SendPermissions(WorldSession* session) const; void SendMoneyInfo(WorldSession* session) const; void SendLoginInfo(WorldSession* session); + void SendNewsUpdate(WorldSession* session); // Load from DB bool LoadFromDB(Field* fields); + void LoadGuildNewsLogFromDB(Field* fields); void LoadRankFromDB(Field* fields); bool LoadMemberFromDB(Field* fields); bool LoadEventLogFromDB(Field* fields); @@ -711,6 +825,7 @@ public: // Broadcasts void BroadcastToGuild(WorldSession* session, bool officerOnly, std::string const& msg, uint32 language = LANG_UNIVERSAL) const; + void BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std::string const& msg, std::string const& prefix) const; void BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const; void BroadcastPacket(WorldPacket* packet) const; @@ -730,6 +845,8 @@ public: bool AddMember(uint64 guid, uint8 rankId = GUILD_RANK_NONE); void DeleteMember(uint64 guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); bool ChangeMemberRank(uint64 guid, uint8 newRank); + bool IsMember(uint64 guid) const; + uint32 GetMembersCount() { return m_members.size(); } // Bank void SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount); @@ -738,7 +855,22 @@ public: // Bank tabs void SetBankTabText(uint8 tabId, std::string const& text); - void ResetTimes(); + AchievementMgr<Guild>& GetAchievementMgr() { return m_achievementMgr; } + AchievementMgr<Guild> const& GetAchievementMgr() const { return m_achievementMgr; } + + // Guild leveling + uint8 GetLevel() const { return _level; } + void GiveXP(uint32 xp, Player* source); + uint64 GetExperience() const { return _experience; } + uint64 GetTodayExperience() const { return _todayExperience; } + + void AddGuildNews(uint8 type, uint64 guid, uint32 flags, uint32 value); + + EmblemInfo const& GetEmblemInfo() const { return m_emblemInfo; } + void ResetTimes(bool weekly); + + bool HasAchieved(uint32 achievementId) const; + void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, Unit* unit, Player* player); protected: uint32 m_id; @@ -759,12 +891,18 @@ protected: // These are actually ordered lists. The first element is the oldest entry. LogHolder* m_eventLog; LogHolder* m_bankEventLog[GUILD_BANK_MAX_TABS + 1]; + LogHolder* m_newsLog; + AchievementMgr<Guild> m_achievementMgr; + + uint8 _level; + uint64 _experience; + uint64 _todayExperience; private: inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } inline const RankInfo* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; } inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; } - inline bool _HasRankRight(Player* player, uint32 right) const + inline bool _HasRankRight(Player const* player, uint32 right) const { if (player) if (Member const* member = GetMember(player->GetGUID())) @@ -842,11 +980,10 @@ private: void _MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount); bool _DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount = 0); - void _SendBankContent(WorldSession* session, uint8 tabId) const; - void _SendBankMoneyUpdate(WorldSession* session) const; void _SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) const; void _SendBankContentUpdate(uint8 tabId, SlotIds slots) const; - void _SendBankList(WorldSession* session = NULL, uint8 tabId = 0, bool sendFullSlots = false, SlotIds *slots = NULL) const; + void SendGuildReputationWeeklyCap(WorldSession* session, uint32 reputation) const; + void SendGuildRanksUpdate(uint64 setterGuid, uint64 targetGuid, uint32 rank); void _BroadcastEvent(GuildEvents guildEvent, uint64 guid, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL) const; }; diff --git a/src/server/game/Guilds/GuildFinderMgr.cpp b/src/server/game/Guilds/GuildFinderMgr.cpp new file mode 100644 index 00000000000..024f4f4bd38 --- /dev/null +++ b/src/server/game/Guilds/GuildFinderMgr.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ObjectMgr.h" +#include "GuildFinderMgr.h" +#include "GuildMgr.h" +#include "World.h" + +GuildFinderMgr::GuildFinderMgr() +{ +} + +GuildFinderMgr::~GuildFinderMgr() +{ +} + +void GuildFinderMgr::LoadFromDB() +{ + LoadGuildSettings(); + LoadMembershipRequests(); +} + +void GuildFinderMgr::LoadGuildSettings() +{ + TC_LOG_INFO("server.loading", "Loading guild finder guild-related settings..."); + // 0 1 2 3 4 5 6 7 + QueryResult result = CharacterDatabase.Query("SELECT gfgs.guildId, gfgs.availability, gfgs.classRoles, gfgs.interests, gfgs.level, gfgs.listed, gfgs.comment, c.race " + "FROM guild_finder_guild_settings gfgs " + "LEFT JOIN guild_member gm ON gm.guildid=gfgs.guildId " + "LEFT JOIN characters c ON c.guid = gm.guid LIMIT 1"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 guild finder guild-related settings. Table `guild_finder_guild_settings` is empty."); + return; + } + + uint32 count = 0; + uint32 oldMSTime = getMSTime(); + do + { + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + uint8 availability = fields[1].GetUInt8(); + uint8 classRoles = fields[2].GetUInt8(); + uint8 interests = fields[3].GetUInt8(); + uint8 level = fields[4].GetUInt8(); + bool listed = (fields[5].GetUInt8() != 0); + std::string comment = fields[6].GetString(); + + TeamId guildTeam = TEAM_ALLIANCE; + if (ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(fields[7].GetUInt8())) + if (raceEntry->TeamID == 1) + guildTeam = TEAM_HORDE; + + LFGuildSettings settings(listed, guildTeam, guildId, classRoles, availability, interests, level, comment); + _guildSettings[guildId] = settings; + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u guild finder guild-related settings in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void GuildFinderMgr::LoadMembershipRequests() +{ + TC_LOG_INFO("server.loading", "Loading guild finder membership requests..."); + // 0 1 2 3 4 5 6 + QueryResult result = CharacterDatabase.Query("SELECT guildId, playerGuid, availability, classRole, interests, comment, submitTime " + "FROM guild_finder_applicant"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 guild finder membership requests. Table `guild_finder_applicant` is empty."); + return; + } + + uint32 count = 0; + uint32 oldMSTime = getMSTime(); + do + { + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + uint32 playerId = fields[1].GetUInt32(); + uint8 availability = fields[2].GetUInt8(); + uint8 classRoles = fields[3].GetUInt8(); + uint8 interests = fields[4].GetUInt8(); + std::string comment = fields[5].GetString(); + uint32 submitTime = fields[6].GetUInt32(); + + MembershipRequest request(playerId, guildId, availability, classRoles, interests, comment, time_t(submitTime)); + + _membershipRequests[guildId].push_back(request); + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u guild finder membership requests in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void GuildFinderMgr::AddMembershipRequest(uint32 guildGuid, MembershipRequest const& request) +{ + _membershipRequests[guildGuid].push_back(request); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GUILD_FINDER_APPLICANT); + stmt->setUInt32(0, request.GetGuildId()); + stmt->setUInt32(1, request.GetPlayerGUID()); + stmt->setUInt8(2, request.GetAvailability()); + stmt->setUInt8(3, request.GetClassRoles()); + stmt->setUInt8(4, request.GetInterests()); + stmt->setString(5, request.GetComment()); + stmt->setUInt32(6, request.GetSubmitTime()); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); + + // Notify the applicant his submittion has been added + if (Player* player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(request.GetPlayerGUID(), 0, HIGHGUID_PLAYER))) + SendMembershipRequestListUpdate(*player); + + // Notify the guild master and officers the list changed + if (Guild* guild = sGuildMgr->GetGuildById(guildGuid)) + SendApplicantListUpdate(*guild); +} + +void GuildFinderMgr::RemoveAllMembershipRequestsFromPlayer(uint32 playerId) +{ + for (MembershipRequestStore::iterator itr = _membershipRequests.begin(); itr != _membershipRequests.end(); ++itr) + { + std::vector<MembershipRequest>::iterator itr2 = itr->second.begin(); + for (; itr2 != itr->second.end(); ++itr2) + if (itr2->GetPlayerGUID() == playerId) + break; + + if (itr2 == itr->second.end()) + continue; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); + stmt->setUInt32(0, itr2->GetGuildId()); + stmt->setUInt32(1, itr2->GetPlayerGUID()); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); + itr->second.erase(itr2); + + // Notify the guild master and officers the list changed + if (Guild* guild = sGuildMgr->GetGuildById(itr->first)) + SendApplicantListUpdate(*guild); + } +} + +void GuildFinderMgr::RemoveMembershipRequest(uint32 playerId, uint32 guildId) +{ + std::vector<MembershipRequest>::iterator itr = _membershipRequests[guildId].begin(); + for (; itr != _membershipRequests[guildId].end(); ++itr) + if (itr->GetPlayerGUID() == playerId) + break; + + if (itr == _membershipRequests[guildId].end()) + return; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); + stmt->setUInt32(0, itr->GetGuildId()); + stmt->setUInt32(1, itr->GetPlayerGUID()); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); + + _membershipRequests[guildId].erase(itr); + + // Notify the applicant his submittion has been removed + if (Player* player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(playerId, 0, HIGHGUID_PLAYER))) + SendMembershipRequestListUpdate(*player); + + // Notify the guild master and officers the list changed + if (Guild* guild = sGuildMgr->GetGuildById(guildId)) + SendApplicantListUpdate(*guild); +} + +std::list<MembershipRequest> GuildFinderMgr::GetAllMembershipRequestsForPlayer(uint32 playerGuid) +{ + std::list<MembershipRequest> resultSet; + for (MembershipRequestStore::const_iterator itr = _membershipRequests.begin(); itr != _membershipRequests.end(); ++itr) + { + std::vector<MembershipRequest> const& guildReqs = itr->second; + for (std::vector<MembershipRequest>::const_iterator itr2 = guildReqs.begin(); itr2 != guildReqs.end(); ++itr2) + { + if (itr2->GetPlayerGUID() == playerGuid) + { + resultSet.push_back(*itr2); + break; + } + } + } + return resultSet; +} + +uint8 GuildFinderMgr::CountRequestsFromPlayer(uint32 playerId) +{ + uint8 result = 0; + for (MembershipRequestStore::const_iterator itr = _membershipRequests.begin(); itr != _membershipRequests.end(); ++itr) + { + for (std::vector<MembershipRequest>::const_iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + { + if (itr2->GetPlayerGUID() != playerId) + continue; + ++result; + break; + } + } + return result; +} + +LFGuildStore GuildFinderMgr::GetGuildsMatchingSetting(LFGuildPlayer& settings, TeamId faction) +{ + LFGuildStore resultSet; + for (LFGuildStore::const_iterator itr = _guildSettings.begin(); itr != _guildSettings.end(); ++itr) + { + LFGuildSettings const& guildSettings = itr->second; + + if (guildSettings.GetTeam() != faction) + continue; + + if (!(guildSettings.GetAvailability() & settings.GetAvailability())) + continue; + + if (!(guildSettings.GetClassRoles() & settings.GetClassRoles())) + continue; + + if (!(guildSettings.GetInterests() & settings.GetInterests())) + continue; + + if (!(guildSettings.GetLevel() & settings.GetLevel())) + continue; + + resultSet.insert(std::make_pair(itr->first, guildSettings)); + } + + return resultSet; +} + +bool GuildFinderMgr::HasRequest(uint32 playerId, uint32 guildId) +{ + for (std::vector<MembershipRequest>::const_iterator itr = _membershipRequests[guildId].begin(); itr != _membershipRequests[guildId].end(); ++itr) + if (itr->GetPlayerGUID() == playerId) + return true; + return false; +} + +void GuildFinderMgr::SetGuildSettings(uint32 guildGuid, LFGuildSettings const& settings) +{ + _guildSettings[guildGuid] = settings; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GUILD_FINDER_GUILD_SETTINGS); + stmt->setUInt32(0, settings.GetGUID()); + stmt->setUInt8(1, settings.GetAvailability()); + stmt->setUInt8(2, settings.GetClassRoles()); + stmt->setUInt8(3, settings.GetInterests()); + stmt->setUInt8(4, settings.GetLevel()); + stmt->setUInt8(5, settings.IsListed()); + stmt->setString(6, settings.GetComment()); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); +} + +void GuildFinderMgr::DeleteGuild(uint32 guildId) +{ + std::vector<MembershipRequest>::iterator itr = _membershipRequests[guildId].begin(); + while (itr != _membershipRequests[guildId].end()) + { + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + uint32 applicant = itr->GetPlayerGUID(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_APPLICANT); + stmt->setUInt32(0, itr->GetGuildId()); + stmt->setUInt32(1, applicant); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_FINDER_GUILD_SETTINGS); + stmt->setUInt32(0, itr->GetGuildId()); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); + + // Notify the applicant his submition has been removed + if (Player* player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(applicant, 0, HIGHGUID_PLAYER))) + SendMembershipRequestListUpdate(*player); + + ++itr; + } + + _membershipRequests.erase(guildId); + _guildSettings.erase(guildId); + + // Notify the guild master the list changed (even if he's not a GM any more, not sure if needed) + if (Guild* guild = sGuildMgr->GetGuildById(guildId)) + SendApplicantListUpdate(*guild); +} + +void GuildFinderMgr::SendApplicantListUpdate(Guild& guild) +{ + WorldPacket data(SMSG_LF_GUILD_APPLICANT_LIST_UPDATED, 0); + if (Player* player = ObjectAccessor::FindPlayer(guild.GetLeaderGUID())) + player->SendDirectMessage(&data); + guild.BroadcastPacketToRank(&data, GR_OFFICER); +} + +void GuildFinderMgr::SendMembershipRequestListUpdate(Player& player) +{ + WorldPacket data(SMSG_LF_GUILD_APPLICATIONS_LIST_CHANGED, 0); + player.SendDirectMessage(&data); +} diff --git a/src/server/game/Guilds/GuildFinderMgr.h b/src/server/game/Guilds/GuildFinderMgr.h new file mode 100644 index 00000000000..9fc62d43935 --- /dev/null +++ b/src/server/game/Guilds/GuildFinderMgr.h @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __TRINITY_GUILDFINDER_H +#define __TRINITY_GUILDFINDER_H + +#include "Common.h" +#include "World.h" +#include "GuildMgr.h" + +enum GuildFinderOptionsInterest +{ + INTEREST_QUESTING = 0x01, + INTEREST_DUNGEONS = 0x02, + INTEREST_RAIDS = 0x04, + INTEREST_PVP = 0x08, + INTEREST_ROLE_PLAYING = 0x10, + ALL_INTERESTS = INTEREST_QUESTING | INTEREST_DUNGEONS | INTEREST_RAIDS | INTEREST_PVP | INTEREST_ROLE_PLAYING +}; + +enum GuildFinderOptionsAvailability +{ + AVAILABILITY_WEEKDAYS = 0x1, + AVAILABILITY_WEEKENDS = 0x2, + AVAILABILITY_ALWAYS = AVAILABILITY_WEEKDAYS | AVAILABILITY_WEEKENDS +}; + +enum GuildFinderOptionsRoles +{ + GUILDFINDER_ROLE_TANK = 0x1, + GUILDFINDER_ROLE_HEALER = 0x2, + GUILDFINDER_ROLE_DPS = 0x4, + GUILDFINDER_ALL_ROLES = GUILDFINDER_ROLE_TANK | GUILDFINDER_ROLE_HEALER | GUILDFINDER_ROLE_DPS +}; + +enum GuildFinderOptionsLevel +{ + ANY_FINDER_LEVEL = 0x1, + MAX_FINDER_LEVEL = 0x2, + ALL_GUILDFINDER_LEVELS = ANY_FINDER_LEVEL | MAX_FINDER_LEVEL +}; + +/// Holds all required informations about a membership request +struct MembershipRequest +{ + public: + MembershipRequest(MembershipRequest const& settings) : _comment(settings.GetComment()) + { + _availability = settings.GetAvailability(); + _classRoles = settings.GetClassRoles(); + _interests = settings.GetInterests(); + _guildId = settings.GetGuildId(); + _playerGUID = settings.GetPlayerGUID(); + _time = settings.GetSubmitTime(); + } + + MembershipRequest(uint32 playerGUID, uint32 guildId, uint32 availability, uint32 classRoles, uint32 interests, std::string& comment, time_t submitTime) : + _comment(comment), _guildId(guildId), _playerGUID(playerGUID), _availability(availability), + _classRoles(classRoles), _interests(interests), _time(submitTime) {} + + MembershipRequest() : _guildId(0), _playerGUID(0), _availability(0), _classRoles(0), + _interests(0), _time(time(NULL)) {} + + uint32 GetGuildId() const { return _guildId; } + uint32 GetPlayerGUID() const { return _playerGUID; } + uint8 GetAvailability() const { return _availability; } + uint8 GetClassRoles() const { return _classRoles; } + uint8 GetInterests() const { return _interests; } + uint8 GetClass() const { return sWorld->GetCharacterNameData(GetPlayerGUID())->m_class; } + uint8 GetLevel() const { return sWorld->GetCharacterNameData(GetPlayerGUID())->m_level; } + time_t GetSubmitTime() const { return _time; } + time_t GetExpiryTime() const { return time_t(_time + 30 * 24 * 3600); } // Adding 30 days + std::string const& GetComment() const { return _comment; } + std::string const& GetName() const { return sWorld->GetCharacterNameData(GetPlayerGUID())->m_name; } + private: + std::string _comment; + + uint32 _guildId; + uint32 _playerGUID; + + uint8 _availability; + uint8 _classRoles; + uint8 _interests; + + time_t _time; +}; + +/// Holds all informations about a player's finder settings. _NOT_ stored in database. +struct LFGuildPlayer +{ + public: + LFGuildPlayer() + { + _guid = 0; + _roles = 0; + _availability = 0; + _interests = 0; + _level = 0; + } + + LFGuildPlayer(uint32 guid, uint8 role, uint8 availability, uint8 interests, uint8 level) + { + _guid = guid; + _roles = role; + _availability = availability; + _interests = interests; + _level = level; + } + + LFGuildPlayer(uint32 guid, uint8 role, uint8 availability, uint8 interests, uint8 level, std::string& comment) : _comment(comment) + { + _guid = guid; + _roles = role; + _availability = availability; + _interests = interests; + _level = level; + } + + LFGuildPlayer(LFGuildPlayer const& settings) : _comment(settings.GetComment()) + { + _guid = settings.GetGUID(); + _roles = settings.GetClassRoles(); + _availability = settings.GetAvailability(); + _interests = settings.GetInterests(); + _level = settings.GetLevel(); + } + + uint32 GetGUID() const { return _guid; } + uint8 GetClassRoles() const { return _roles; } + uint8 GetAvailability() const { return _availability; } + uint8 GetInterests() const { return _interests; } + uint8 GetLevel() const { return _level; } + std::string const& GetComment() const { return _comment; } + + private: + std::string _comment; + uint32 _guid; + uint8 _roles; + uint8 _availability; + uint8 _interests; + uint8 _level; +}; + +/// Holds settings for a guild in the finder system. Saved to database. +struct LFGuildSettings : public LFGuildPlayer +{ + public: + LFGuildSettings() : LFGuildPlayer(), _listed(false), _team(TEAM_ALLIANCE) {} + + LFGuildSettings(bool listed, TeamId team) : LFGuildPlayer(), _listed(listed), _team(team) {} + + LFGuildSettings(bool listed, TeamId team, uint32 guid, uint8 role, uint8 availability, uint8 interests, uint8 level) : + LFGuildPlayer(guid, role, availability, interests, level), _listed(listed), _team(team) {} + + LFGuildSettings(bool listed, TeamId team, uint32 guid, uint8 role, uint8 availability, uint8 interests, uint8 level, std::string& comment) : + LFGuildPlayer(guid, role, availability, interests, level, comment), _listed(listed), _team(team) {} + + LFGuildSettings(LFGuildSettings const& settings) : + LFGuildPlayer(settings), _listed(settings.IsListed()), _team(settings.GetTeam()) {} + + + bool IsListed() const { return _listed; } + void SetListed(bool state) { _listed = state; } + + TeamId GetTeam() const { return _team; } + private: + bool _listed; + TeamId _team; +}; + +typedef std::map<uint32 /* guildGuid */, LFGuildSettings> LFGuildStore; +typedef std::map<uint32 /* guildGuid */, std::vector<MembershipRequest> > MembershipRequestStore; + +class GuildFinderMgr +{ + private: + GuildFinderMgr(); + ~GuildFinderMgr(); + + LFGuildStore _guildSettings; + + MembershipRequestStore _membershipRequests; + + void LoadGuildSettings(); + void LoadMembershipRequests(); + + public: + void LoadFromDB(); + + /** + * @brief Stores guild settings and begins an asynchronous database insert + * @param guildGuid The guild's database guid. + * @param LFGuildSettings The guild's settings storage. + */ + void SetGuildSettings(uint32 guildGuid, LFGuildSettings const& settings); + + /** + * @brief Returns settings for a guild. + * @param guildGuid The guild's database guid. + */ + LFGuildSettings GetGuildSettings(uint32 guildGuid) { return _guildSettings[guildGuid]; } + + /** + * @brief Files a membership request to a guild + * @param guildGuid The guild's database GUID. + * @param MembershipRequest An object storing all data related to the request. + */ + void AddMembershipRequest(uint32 guildGuid, MembershipRequest const& request); + + /** + * @brief Removes all membership request from a player. + * @param playerId The player's database guid whose application shall be deleted. + */ + void RemoveAllMembershipRequestsFromPlayer(uint32 playerId); + + /** + * @brief Removes a membership request to a guild. + * @param playerId The player's database guid whose application shall be deleted. + * @param guildId The guild's database guid + */ + void RemoveMembershipRequest(uint32 playerId, uint32 guildId); + + /// Wipes everything related to a guild. Used when that guild is disbanded + void DeleteGuild(uint32 guildId); + + /** + * @brief Returns a set of membership requests for a guild + * @param guildGuid The guild's database guid. + */ + std::vector<MembershipRequest> GetAllMembershipRequestsForGuild(uint32 guildGuid) { return _membershipRequests[guildGuid]; } + + /** + * @brief Returns a list of membership requests for a player. + * @param playerGuid The player's database guid. + */ + std::list<MembershipRequest> GetAllMembershipRequestsForPlayer(uint32 playerGuid); + + /** + * @brief Returns a store of guilds matching the settings provided, using bitmask operators. + * @param settings The player's finder settings + * @param teamId The player's faction (TEAM_ALLIANCE or TEAM_HORDE) + */ + LFGuildStore GetGuildsMatchingSetting(LFGuildPlayer& settings, TeamId faction); + + /// Provided a player DB guid and a guild DB guid, determines if a pending request is filed with these keys. + bool HasRequest(uint32 playerId, uint32 guildId); + + /// Counts the amount of pending membership requests, given the player's db guid. + uint8 CountRequestsFromPlayer(uint32 playerId); + + void SendApplicantListUpdate(Guild& guild); + void SendMembershipRequestListUpdate(Player& player); + + static GuildFinderMgr* instance() + { + static GuildFinderMgr instance; + return &instance; + } +}; + +#define sGuildFinderMgr GuildFinderMgr::instance() + +#endif // __TRINITY_GUILDFINDER_H diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index b9cb7d6dce9..bdb0b7dce52 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -37,6 +37,12 @@ void GuildMgr::RemoveGuild(uint32 guildId) GuildStore.erase(guildId); } +void GuildMgr::SaveGuilds() +{ + for (GuildContainer::iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) + itr->second->SaveToDB(); +} + uint32 GuildMgr::GenerateGuildId() { if (NextGuildId >= 0xFFFFFFFE) @@ -57,6 +63,17 @@ Guild* GuildMgr::GetGuildById(uint32 guildId) const return NULL; } +Guild* GuildMgr::GetGuildByGuid(uint64 guid) const +{ + // Full guids are only used when receiving/sending data to client + // everywhere else guild id is used + if (IS_GUILD_GUID(guid)) + if (uint32 guildId = GUID_LOPART(guid)) + return GetGuildById(guildId); + + return NULL; +} + Guild* GuildMgr::GetGuildByName(const std::string& guildName) const { std::string search = guildName; @@ -88,6 +105,13 @@ Guild* GuildMgr::GetGuildByLeader(uint64 guid) const return NULL; } +uint32 GuildMgr::GetXPForGuildLevel(uint8 level) const +{ + if (level < GuildXPperLevel.size()) + return GuildXPperLevel[level]; + return 0; +} + void GuildMgr::LoadGuilds() { // 1. Load all guilds @@ -97,8 +121,8 @@ void GuildMgr::LoadGuilds() // 0 1 2 3 4 5 6 QueryResult result = CharacterDatabase.Query("SELECT g.guildid, g.name, g.leaderguid, g.EmblemStyle, g.EmblemColor, g.BorderStyle, g.BorderColor, " - // 7 8 9 10 11 12 - "g.BackgroundColor, g.info, g.motd, g.createdate, g.BankMoney, COUNT(gbt.guildid) " + // 7 8 9 10 11 12 13 14 15 + "g.BackgroundColor, g.info, g.motd, g.createdate, g.BankMoney, g.level, g.experience, g.todayExperience, COUNT(gbt.guildid) " "FROM guild g LEFT JOIN guild_bank_tab gbt ON g.guildid = gbt.guildid GROUP BY g.guildid ORDER BY g.guildid ASC"); if (!result) @@ -173,13 +197,13 @@ void GuildMgr::LoadGuilds() CharacterDatabase.DirectExecute("DELETE gm FROM guild_member gm LEFT JOIN guild g ON gm.guildId = g.guildId WHERE g.guildId IS NULL"); CharacterDatabase.DirectExecute("DELETE gm FROM guild_member_withdraw gm LEFT JOIN guild_member g ON gm.guid = g.guid WHERE g.guid IS NULL"); - // 0 1 2 3 4 5 6 7 8 9 10 - QueryResult result = CharacterDatabase.Query("SELECT guildid, gm.guid, rank, pnote, offnote, w.tab0, w.tab1, w.tab2, w.tab3, w.tab4, w.tab5, " - // 11 12 13 14 15 16 17 - "w.money, c.name, c.level, c.class, c.zone, c.account, c.logout_time " + // 0 1 2 3 4 5 6 7 8 9 10 + QueryResult result = CharacterDatabase.Query("SELECT gm.guildid, gm.guid, rank, pnote, offnote, w.tab0, w.tab1, w.tab2, w.tab3, w.tab4, w.tab5, " + // 11 12 13 14 15 16 17 18 19 + "w.tab6, w.tab7, w.money, c.name, c.level, c.class, c.zone, c.account, c.logout_time " "FROM guild_member gm " "LEFT JOIN guild_member_withdraw w ON gm.guid = w.guid " - "LEFT JOIN characters c ON c.guid = gm.guid ORDER BY guildid ASC"); + "LEFT JOIN characters c ON c.guid = gm.guid ORDER BY gm.guildid ASC"); if (!result) TC_LOG_INFO("server.loading", ">> Loaded 0 guild members. DB table `guild_member` is empty."); @@ -304,7 +328,39 @@ void GuildMgr::LoadGuilds() } } - // 7. Load all guild bank tabs + // 7. Load all news event logs + TC_LOG_INFO("server.loading", "Loading Guild News..."); + { + uint32 oldMSTime = getMSTime(); + + CharacterDatabase.DirectPExecute("DELETE FROM guild_newslog WHERE LogGuid > %u", sWorld->getIntConfig(CONFIG_GUILD_NEWS_LOG_COUNT)); + + // 0 1 2 3 4 5 6 + QueryResult result = CharacterDatabase.Query("SELECT guildid, LogGuid, EventType, PlayerGuid, Flags, Value, Timestamp FROM guild_newslog ORDER BY TimeStamp DESC, LogGuid DESC"); + + if (!result) + TC_LOG_INFO("server.loading", ">> Loaded 0 guild event logs. DB table `guild_newslog` is empty."); + else + { + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + + if (Guild* guild = GetGuildById(guildId)) + guild->LoadGuildNewsLogFromDB(fields); + + ++count; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u guild new logs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + } + } + + + // 8. Load all guild bank tabs TC_LOG_INFO("server.loading", "Loading guild bank tabs..."); { uint32 oldMSTime = getMSTime(); @@ -338,7 +394,7 @@ void GuildMgr::LoadGuilds() } } - // 8. Fill all guild bank tabs + // 9. Fill all guild bank tabs TC_LOG_INFO("guild", "Filling bank tabs with items..."); { uint32 oldMSTime = getMSTime(); @@ -374,8 +430,25 @@ void GuildMgr::LoadGuilds() } } - // 9. Validate loaded guild data - TC_LOG_INFO("guild", "Validating data of loaded guilds..."); + // 10. Load guild achievements + { + PreparedQueryResult achievementResult; + PreparedQueryResult criteriaResult; + for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_ACHIEVEMENT); + stmt->setUInt32(0, itr->first); + achievementResult = CharacterDatabase.Query(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_ACHIEVEMENT_CRITERIA); + stmt->setUInt32(0, itr->first); + criteriaResult = CharacterDatabase.Query(stmt); + + itr->second->GetAchievementMgr().LoadFromDB(achievementResult, criteriaResult); + } + } + + // 11. Validate loaded guild data + TC_LOG_INFO("misc", "Validating data of loaded guilds..."); { uint32 oldMSTime = getMSTime(); @@ -391,11 +464,112 @@ void GuildMgr::LoadGuilds() } } -void GuildMgr::ResetTimes() +void GuildMgr::LoadGuildXpForLevel() { + uint32 oldMSTime = getMSTime(); + + GuildXPperLevel.resize(sWorld->getIntConfig(CONFIG_GUILD_MAX_LEVEL)); + for (uint8 level = 0; level < sWorld->getIntConfig(CONFIG_GUILD_MAX_LEVEL); ++level) + GuildXPperLevel[level] = 0; + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT lvl, xp_for_next_level FROM guild_xp_for_level"); + + if (!result) + { + TC_LOG_ERROR("server.loading", ">> Loaded 0 xp for guild level definitions. DB table `guild_xp_for_level` is empty."); + return; + } + + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + + uint32 level = fields[0].GetUInt8(); + uint32 requiredXP = fields[1].GetUInt32(); + + if (level >= sWorld->getIntConfig(CONFIG_GUILD_MAX_LEVEL)) + { + TC_LOG_INFO("misc", "Unused (> Guild.MaxLevel in worldserver.conf) level %u in `guild_xp_for_level` table, ignoring.", uint32(level)); + continue; + } + + GuildXPperLevel[level] = requiredXP; + ++count; + + } while (result->NextRow()); + + // fill level gaps + for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_GUILD_MAX_LEVEL); ++level) + { + if (!GuildXPperLevel[level]) + { + TC_LOG_ERROR("sql.sql", "Level %i does not have XP for guild level data. Using data of level [%i] + 1660000.", level+1, level); + GuildXPperLevel[level] = GuildXPperLevel[level - 1] + 1660000; + } + } + + TC_LOG_INFO("server.loading", ">> Loaded %u xp for guild level definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void GuildMgr::LoadGuildRewards() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 2 3 4 + QueryResult result = WorldDatabase.Query("SELECT entry, standing, racemask, price, achievement FROM guild_rewards"); + + if (!result) + { + TC_LOG_ERROR("server.loading", ">> Loaded 0 guild reward definitions. DB table `guild_rewards` is empty."); + return; + } + + uint32 count = 0; + + do + { + GuildReward reward; + Field* fields = result->Fetch(); + reward.Entry = fields[0].GetUInt32(); + reward.Standing = fields[1].GetUInt8(); + reward.Racemask = fields[2].GetInt32(); + reward.Price = fields[3].GetUInt64(); + reward.AchievementId = fields[4].GetUInt32(); + + if (!sObjectMgr->GetItemTemplate(reward.Entry)) + { + TC_LOG_ERROR("server.loading", "Guild rewards constains not existing item entry %u", reward.Entry); + continue; + } + + if (reward.AchievementId != 0 && (!sAchievementMgr->GetAchievement(reward.AchievementId))) + { + TC_LOG_ERROR("server.loading", "Guild rewards constains not existing achievement entry %u", reward.AchievementId); + continue; + } + + if (reward.Standing >= MAX_REPUTATION_RANK) + { + TC_LOG_ERROR("server.loading", "Guild rewards contains wrong reputation standing %u, max is %u", uint32(reward.Standing), MAX_REPUTATION_RANK - 1); + continue; + } + + GuildRewards.push_back(reward); + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u guild reward definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void GuildMgr::ResetTimes(bool week) +{ + CharacterDatabase.Execute(CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RESET_TODAY_EXPERIENCE)); + CharacterDatabase.Execute(CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER_WITHDRAW)); + for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) if (Guild* guild = itr->second) - guild->ResetTimes(); - - CharacterDatabase.DirectExecute("TRUNCATE guild_member_withdraw"); -}
\ No newline at end of file + guild->ResetTimes(week); +} diff --git a/src/server/game/Guilds/GuildMgr.h b/src/server/game/Guilds/GuildMgr.h index 4aa418b7e73..5df59f7e8ea 100644 --- a/src/server/game/Guilds/GuildMgr.h +++ b/src/server/game/Guilds/GuildMgr.h @@ -35,21 +35,34 @@ public: Guild* GetGuildByLeader(uint64 guid) const; Guild* GetGuildById(uint32 guildId) const; + Guild* GetGuildByGuid(uint64 guid) const; Guild* GetGuildByName(std::string const& guildName) const; std::string GetGuildNameById(uint32 guildId) const; + void LoadGuildXpForLevel(); + void LoadGuildRewards(); + void LoadGuilds(); void AddGuild(Guild* guild); void RemoveGuild(uint32 guildId); + void SaveGuilds(); + + void ResetReputationCaps(); + uint32 GenerateGuildId(); void SetNextGuildId(uint32 Id) { NextGuildId = Id; } - void ResetTimes(); + uint32 GetXPForGuildLevel(uint8 level) const; + std::vector<GuildReward> const& GetGuildRewards() const { return GuildRewards; } + + void ResetTimes(bool week); protected: typedef std::unordered_map<uint32, Guild*> GuildContainer; uint32 NextGuildId; GuildContainer GuildStore; + std::vector<uint64> GuildXPperLevel; + std::vector<GuildReward> GuildRewards; }; #define sGuildMgr GuildMgr::instance() diff --git a/src/server/game/Handlers/ArenaTeamHandler.cpp b/src/server/game/Handlers/ArenaTeamHandler.cpp index 3bb3edac500..b2db2fff6c2 100644 --- a/src/server/game/Handlers/ArenaTeamHandler.cpp +++ b/src/server/game/Handlers/ArenaTeamHandler.cpp @@ -83,6 +83,54 @@ void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket& recvData) arenaTeam->Roster(this); } +void WorldSession::HandleArenaTeamCreateOpcode(WorldPacket & recvData) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_ARENA_TEAM_CREATE"); + + uint32 slot, icon, iconcolor, border, bordercolor, background; + std::string name; + + recvData >> slot; + recvData >> iconcolor; + recvData >> bordercolor; + recvData >> border; + recvData >> background; + recvData >> icon; + name = recvData.ReadString(recvData.ReadBits(8)); + + uint8 type = ArenaTeam::GetTypeBySlot(slot); + + if (_player->GetArenaTeamId(slot)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); + return; + } + + if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID); + return; + } + + if (sArenaTeamMgr->GetArenaTeamByName(name)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); + return; + } + + ArenaTeam* arenaTeam = new ArenaTeam; + if (!arenaTeam->Create(GUID_LOPART(_player->GetGUID()), type, name, background, icon, iconcolor, border, bordercolor)) + { + TC_LOG_ERROR("bg.arena", "Arena team create failed."); + delete arenaTeam; + return; + } + + sArenaTeamMgr->AddArenaTeam(arenaTeam); + + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_CREATED); +} + void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "CMSG_ARENA_TEAM_INVITE"); @@ -121,6 +169,12 @@ void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket& recvData) return; } + if (arenaTeam->GetCaptain() != _player->GetGUID()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); + return; + } + if (GetPlayer()->GetArenaTeamId(arenaTeam->GetSlot()) != arenaTeamId) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); @@ -363,20 +417,25 @@ void WorldSession::HandleArenaTeamLeaderOpcode(WorldPacket& recvData) void WorldSession::SendArenaTeamCommandResult(uint32 teamAction, const std::string& team, const std::string& player, uint32 errorId) { - WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+team.length()+1+player.length()+1+4); + WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 2 + team.length() + player.length() + 4 + 4); + + data.WriteBits(player.length(), 7); + data.WriteBits(team.length(), 8); + data.FlushBits(); + + data.WriteString(player); data << uint32(teamAction); - data << team; - data << player; data << uint32(errorId); + data.WriteString(team); SendPacket(&data); } void WorldSession::SendNotInArenaTeamPacket(uint8 type) { - WorldPacket data(SMSG_ARENA_ERROR, 4+1); // 886 - You are not in a %uv%u arena team - uint32 unk = 0; - data << uint32(unk); // unk(0) - if (!unk) + WorldPacket data(SMSG_ARENA_ERROR, 4+1); + uint32 error = 0; + data << uint32(error); // 0 = ERR_ARENA_NO_TEAM_II, 1 = ERR_ARENA_EXPIRED_CAIS, 2 = ERR_LFG_CANT_USE_BATTLEGROUND + if (!error) data << uint8(type); // team type (2=2v2, 3=3v3, 5=5v5), can be used for custom types... SendPacket(&data); } diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index 86fa0429cce..12bc18298b7 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -71,14 +71,29 @@ void WorldSession::SendAuctionHello(uint64 guid, Creature* unit) } //call this method when player bids, creates, or deletes auction -void WorldSession::SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError) +void WorldSession::SendAuctionCommandResult(AuctionEntry* auction, uint32 action, uint32 errorCode, uint32 bidError) { - WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 16); - data << auctionId; - data << Action; - data << ErrorCode; - if (!ErrorCode && Action) - data << bidError; //when bid, then send 0, once... + WorldPacket data(SMSG_AUCTION_COMMAND_RESULT); + data << uint32(auction ? auction->Id : 0); + data << uint32(action); + data << uint32(errorCode); + + switch (errorCode) + { + case ERR_AUCTION_OK: + if (action == AUCTION_PLACE_BID) + data << uint64(auction->bid ? auction->GetAuctionOutBid() : 0); + break; + case ERR_AUCTION_INVENTORY: + data << uint32(bidError); + break; + case ERR_AUCTION_HIGHER_BID: + data << uint64(auction->bidder); + data << uint64(auction->bid); + data << uint64(auction->bid ? auction->GetAuctionOutBid() : 0); + break; + } + SendPacket(&data); } @@ -89,32 +104,41 @@ void WorldSession::SendAuctionBidderNotification(uint32 location, uint32 auction data << uint32(location); data << uint32(auctionId); data << uint64(bidder); - data << uint32(bidSum); - data << uint32(diff); + data << uint64(bidSum); + data << uint64(diff); data << uint32(itemEntry); data << uint32(0); SendPacket(&data); } -//this void causes on client to display: "Your auction sold" +// this void causes on client to display: "Your auction sold" void WorldSession::SendAuctionOwnerNotification(AuctionEntry* auction) { - WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, (8*4)); + WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, 40); data << uint32(auction->Id); - data << uint32(auction->bid); - data << uint32(0); //unk - data << uint64(0); //unk (bidder guid?) + data << uint64(auction->bid); + data << uint64(0); //unk + data << uint64(0); //unk data << uint32(auction->itemEntry); - data << uint32(0); //unk - data << float(0); //unk (time?) + data << uint32(0); //unk + data << float(0); //unk + SendPacket(&data); +} + +void WorldSession::SendAuctionRemovedNotification(uint32 auctionId, uint32 itemEntry, int32 randomPropertyId) +{ + WorldPacket data(SMSG_AUCTION_REMOVED_NOTIFICATION, (4+4+4)); + data << uint32(auctionId); + data << uint32(itemEntry); + data << uint32(randomPropertyId); SendPacket(&data); } //this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) { - uint64 auctioneer; - uint32 itemsCount, etime, bid, buyout; + uint64 auctioneer, bid, buyout; + uint32 itemsCount, etime; recvData >> auctioneer; recvData >> itemsCount; @@ -125,7 +149,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) if (itemsCount > MAX_AUCTION_ITEMS) { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); recvData.rfinish(); return; } @@ -152,7 +176,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) if (bid > MAX_MONEY_AMOUNT || buyout > MAX_MONEY_AMOUNT) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Player %s (GUID %u) attempted to sell item with higher price than max gold amount.", _player->GetName().c_str(), _player->GetGUIDLow()); - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } @@ -197,7 +221,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) if (!item) { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_ITEM_NOT_FOUND); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_ITEM_NOT_FOUND); return; } @@ -208,7 +232,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || item->GetCount() < count[i] || itemEntry != item->GetTemplate()->ItemId) { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } @@ -218,7 +242,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) if (!finalCount) { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } @@ -241,7 +265,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) if (item->GetMaxStackCount() < finalCount) { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } @@ -252,9 +276,9 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); - if (!_player->HasEnoughMoney(deposit)) + if (!_player->HasEnoughMoney((uint64)deposit)) { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } @@ -287,7 +311,10 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; - TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(), AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); + TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) " + "to auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", + _player->GetName().c_str(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(), + AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); @@ -300,7 +327,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); - SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); + SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } @@ -310,7 +337,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) if (!newItem) { TC_LOG_ERROR("network", "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } @@ -334,7 +361,10 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; - TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); + TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to " + "auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", + _player->GetName().c_str(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), + newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); @@ -372,7 +402,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); - SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); + SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } @@ -380,19 +410,20 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) _player->ModifyMoney(-int32(deposit)); } -//this function is called when client bids or buys out auction +// this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_PLACE_BID"); uint64 auctioneer; uint32 auctionId; - uint32 price; + uint64 price; recvData >> auctioneer; - recvData >> auctionId >> price; + recvData >> auctionId; + recvData >> price; if (!auctionId || !price) - return; //check for cheaters + return; // check for cheaters Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) @@ -413,18 +444,18 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) if (!auction || auction->owner == player->GetGUIDLow()) { //you cannot bid your own auction: - SendAuctionCommandResult(0, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); + SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; } // impossible have online own another character (use this for speedup check in case online owner) - Player* auction_owner = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); + /*Player* auction_owner = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); if (!auction_owner && sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == player->GetSession()->GetAccountId()) { //you cannot bid your another character auction: - SendAuctionCommandResult(0, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); + SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; - } + }*/ // cheating if (price <= auction->bid || price < auction->startbid) @@ -434,14 +465,15 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) if ((price < auction->buyout || auction->buyout == 0) && price < auction->bid + auction->GetAuctionOutBid()) { - //auction has already higher bid, client tests it! + // client already test it but just in case ... + SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_HIGHER_BID); return; } if (!player->HasEnoughMoney(price)) { - //you don't have enought money!, client tests! - //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); + // client already test it but just in case ... + SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } @@ -452,16 +484,16 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) if (auction->bidder > 0) { if (auction->bidder == player->GetGUIDLow()) - player->ModifyMoney(-int32(price - auction->bid)); + player->ModifyMoney(-int64(price - auction->bid)); else { // mail to last bidder and return money sAuctionMgr->SendAuctionOutbiddedMail(auction, price, GetPlayer(), trans); - player->ModifyMoney(-int32(price)); + player->ModifyMoney(-int64(price)); } } else - player->ModifyMoney(-int32(price)); + player->ModifyMoney(-int64(price)); auction->bidder = player->GetGUIDLow(); auction->bid = price; @@ -473,16 +505,16 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) stmt->setUInt32(2, auction->Id); trans->Append(stmt); - SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, ERR_AUCTION_OK, 0); + SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); } else { //buyout: if (player->GetGUIDLow() == auction->bidder) - player->ModifyMoney(-int32(auction->buyout - auction->bid)); + player->ModifyMoney(-int64(auction->buyout - auction->bid)); else { - player->ModifyMoney(-int32(auction->buyout)); + player->ModifyMoney(-int64(auction->buyout)); if (auction->bidder) //buyout for bidded auction .. sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, GetPlayer(), trans); } @@ -495,7 +527,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); sAuctionMgr->SendAuctionWonMail(auction, trans); - SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, ERR_AUCTION_OK); + SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); auction->DeleteFromDB(trans); @@ -516,7 +548,6 @@ void WorldSession::HandleAuctionRemoveItem(WorldPacket& recvData) uint32 auctionId; recvData >> auctioneer; recvData >> auctionId; - //TC_LOG_DEBUG("Cancel AUCTION AuctionID: %u", auctionId); Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) @@ -543,11 +574,10 @@ void WorldSession::HandleAuctionRemoveItem(WorldPacket& recvData) if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid { uint32 auctionCut = auction->GetAuctionCut(); - if (!player->HasEnoughMoney(auctionCut)) //player doesn't have enough money, maybe message needed + if (!player->HasEnoughMoney((uint64)auctionCut)) //player doesn't have enough money, maybe message needed return; - //some auctionBidderNotification would be needed, but don't know that parts.. - sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans); - player->ModifyMoney(-int32(auctionCut)); + sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans, pItem); + player->ModifyMoney(-int64(auctionCut)); } // item will deleted or added to received mail list @@ -557,21 +587,21 @@ void WorldSession::HandleAuctionRemoveItem(WorldPacket& recvData) } else { - TC_LOG_ERROR("network", "Auction id: %u has non-existed item (item guid : %u)!!!", auction->Id, auction->itemGUIDLow); - SendAuctionCommandResult(0, AUCTION_CANCEL, ERR_AUCTION_DATABASE_ERROR); + TC_LOG_ERROR("network", "Auction id: %u got non existing item (item guid : %u)!", auction->Id, auction->itemGUIDLow); + SendAuctionCommandResult(NULL, AUCTION_CANCEL, ERR_AUCTION_DATABASE_ERROR); return; } } else { - SendAuctionCommandResult(0, AUCTION_CANCEL, ERR_AUCTION_DATABASE_ERROR); + SendAuctionCommandResult(NULL, AUCTION_CANCEL, ERR_AUCTION_DATABASE_ERROR); //this code isn't possible ... maybe there should be assert - TC_LOG_ERROR("network", "CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", player->GetGUIDLow(), auctionId); + TC_LOG_ERROR("network", "CHEATER: %u tried to cancel auction (id: %u) of another player or auction is NULL", player->GetGUIDLow(), auctionId); return; } //inform player, that auction is removed - SendAuctionCommandResult(auction->Id, AUCTION_CANCEL, ERR_AUCTION_OK); + SendAuctionCommandResult(auction, AUCTION_CANCEL, ERR_AUCTION_OK); // Now remove the auction @@ -618,7 +648,7 @@ void WorldSession::HandleAuctionListBidderItems(WorldPacket& recvData) WorldPacket data(SMSG_AUCTION_BIDDER_LIST_RESULT, (4+4+4)); Player* player = GetPlayer(); - data << (uint32) 0; //add 0 as count + data << uint32(0); //add 0 as count uint32 count = 0; uint32 totalcount = 0; while (outbiddedCount > 0) //add all data, which client requires @@ -637,7 +667,7 @@ void WorldSession::HandleAuctionListBidderItems(WorldPacket& recvData) auctionHouse->BuildListBidderItems(data, player, count, totalcount); data.put<uint32>(0, count); // add count to placeholder data << totalcount; - data << (uint32)300; //unk 2.3.0 + data << uint32(300); //unk 2.3.0 SendPacket(&data); } @@ -666,15 +696,15 @@ void WorldSession::HandleAuctionListOwnerItems(WorldPacket& recvData) AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); WorldPacket data(SMSG_AUCTION_OWNER_LIST_RESULT, (4+4+4)); - data << (uint32) 0; // amount place holder + data << uint32(0); // amount place holder uint32 count = 0; uint32 totalcount = 0; auctionHouse->BuildListOwnerItems(data, _player, count, totalcount); data.put<uint32>(0, count); - data << (uint32) totalcount; - data << (uint32) 0; + data << uint32(totalcount); + data << uint32(0); SendPacket(&data); } @@ -697,15 +727,11 @@ void WorldSession::HandleAuctionListItems(WorldPacket& recvData) recvData >> quality >> usable; recvData.read_skip<uint8>(); // unk + recvData.read_skip<uint8>(); // unk // this block looks like it uses some lame byte packing or similar... - uint8 unkCnt; - recvData >> unkCnt; - for (uint8 i = 0; i < unkCnt; i++) - { - recvData.read_skip<uint8>(); + for (uint8 i = 0; i < 15; i++) recvData.read_skip<uint8>(); - } Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) @@ -720,13 +746,13 @@ void WorldSession::HandleAuctionListItems(WorldPacket& recvData) AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); - //TC_LOG_DEBUG("Auctionhouse search (GUID: %u TypeId: %u)",, list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", + //TC_LOG_DEBUG("misc", "Auctionhouse search (GUID: %u TypeId: %u)",, list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", // GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid)), listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable); WorldPacket data(SMSG_AUCTION_LIST_RESULT, (4+4+4)); uint32 count = 0; uint32 totalcount = 0; - data << (uint32) 0; + data << uint32(0); // converting string that we try to find to lower case std::wstring wsearchedname; @@ -741,8 +767,8 @@ void WorldSession::HandleAuctionListItems(WorldPacket& recvData) count, totalcount); data.put<uint32>(0, count); - data << (uint32) totalcount; - data << (uint32) 300; // unk 2.3.0 const? + data << uint32(totalcount); + data << uint32(300); //unk 2.3.0 SendPacket(&data); } @@ -760,7 +786,7 @@ void WorldSession::HandleAuctionListPendingSales(WorldPacket& recvData) { data << ""; // string data << ""; // string - data << uint32(0); + data << uint64(0); data << uint32(0); data << float(0); }*/ diff --git a/src/server/game/Handlers/AuthHandler.cpp b/src/server/game/Handlers/AuthHandler.cpp index 70b0d541e6c..5fafeea9991 100644 --- a/src/server/game/Handlers/AuthHandler.cpp +++ b/src/server/game/Handlers/AuthHandler.cpp @@ -19,20 +19,28 @@ #include "WorldSession.h" #include "WorldPacket.h" -void WorldSession::SendAuthResponse(uint8 code, bool shortForm, uint32 queuePos) +void WorldSession::SendAuthResponse(uint8 code, bool queued, uint32 queuePos) { - WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1 + (shortForm ? 0 : (4 + 1))); - packet << uint8(code); + WorldPacket packet(SMSG_AUTH_RESPONSE, 1 /*bits*/ + 4 + 1 + 4 + 1 + 4 + 1 + 1 + (queued ? 4 : 0)); + packet.WriteBit(queued); + if (queued) + packet.WriteBit(0); + + packet.WriteBit(1); // has account info + + packet.FlushBits(); + + // account info packet << uint32(0); // BillingTimeRemaining - packet << uint8(0); // BillingPlanFlags + packet << uint8(Expansion()); // 0 - normal, 1 - TBC, 2 - WOTLK, 3 - CATA; must be set in database manually for each account + packet << uint32(0); + packet << uint8(Expansion()); // Unknown, these two show the same packet << uint32(0); // BillingTimeRested - packet << uint8(Expansion()); // 0 - normal, 1 - TBC, 2 - WOTLK, must be set in database manually for each account + packet << uint8(0); // BillingPlanFlags - if (!shortForm) - { + packet << uint8(code); + if (queued) packet << uint32(queuePos); // Queue position - packet << uint8(0); // Realm has a free character migration - bool - } SendPacket(&packet); } diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 95e4dd3b5e0..faae8ef3ba0 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -66,23 +66,41 @@ void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket& recvData) void WorldSession::SendBattleGroundList(uint64 guid, BattlegroundTypeId bgTypeId) { WorldPacket data; - sBattlegroundMgr->BuildBattlegroundListPacket(&data, guid, _player, bgTypeId, 0); + sBattlegroundMgr->BuildBattlegroundListPacket(&data, guid, _player, bgTypeId); SendPacket(&data); } void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) { - uint64 guid; uint32 bgTypeId_; uint32 instanceId; - uint8 joinAsGroup; + uint8 asGroup; bool isPremade = false; Group* grp = NULL; - - recvData >> guid; // battlemaster guid - recvData >> bgTypeId_; // battleground type id (DBC id) - recvData >> instanceId; // instance id, 0 if First Available selected - recvData >> joinAsGroup; // join as group + ObjectGuid guid; + + recvData >> instanceId; // Instance Id + guid[2] = recvData.ReadBit(); + guid[0] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + guid[1] = recvData.ReadBit(); + guid[5] = recvData.ReadBit(); + asGroup = recvData.ReadBit(); // As Group + guid[4] = recvData.ReadBit(); + guid[6] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + + recvData.ReadByteSeq(guid[2]); + recvData.ReadByteSeq(guid[6]); + recvData.ReadByteSeq(guid[4]); + recvData.ReadByteSeq(guid[3]); + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[5]); + recvData.ReadByteSeq(guid[1]); + + //extract from guid + bgTypeId_ = GUID_LOPART(guid); if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { @@ -95,10 +113,9 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); return; } - BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); + //TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID:"UI64FMTD" TypeId:%u)", guid, bgTypeId_); // can do this, since it's battleground, not arena BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0); @@ -123,16 +140,15 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) if (!bracketEntry) return; - GroupJoinBattlegroundResult err; + GroupJoinBattlegroundResult err = ERR_BATTLEGROUND_NONE; // check queue conditions - if (!joinAsGroup) + if (!asGroup) { if (GetPlayer()->isUsingLfg()) { - // player is using dungeon finder or raid finder WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_LFG_CANT_USE_BATTLEGROUND); + sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_LFG_CANT_USE_BATTLEGROUND); GetPlayer()->GetSession()->SendPacket(&data); return; } @@ -141,7 +157,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) if (!_player->CanJoinToBattleground(bg)) { WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); + sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data); return; } @@ -150,7 +166,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) { // player is already in random queue WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_RANDOM_BG); + sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_IN_RANDOM_BG); _player->GetSession()->SendPacket(&data); return; } @@ -159,7 +175,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) { // player is already in queue, can't start random queue WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_NON_RANDOM_BG); + sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_IN_NON_RANDOM_BG); _player->GetSession()->SendPacket(&data); return; } @@ -173,33 +189,37 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) if (!_player->HasFreeBattlegroundQueueId()) { WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); + sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_BATTLEGROUND_TOO_MANY_QUEUES); _player->GetSession()->SendPacket(&data); return; } BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - // already checked if queueSlot is valid, now just get it uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); - WorldPacket data; - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType, 0); + // add joined time data + _player->AddBattlegroundQueueJoinTime(bgTypeId, ginfo->JoinTime); + + WorldPacket data; // send status packet (in queue) + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_WAIT_QUEUE, avgTime, ginfo->JoinTime, ginfo->ArenaType); SendPacket(&data); + TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName().c_str()); } else { grp = _player->GetGroup(); - // no group found, error + if (!grp) return; + if (grp->GetLeaderGUID() != _player->GetGUID()) return; + err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); @@ -207,7 +227,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) GroupQueueInfo* ginfo = NULL; uint32 avgTime = 0; - if (err > 0) + if (!err) { TC_LOG_DEBUG("bg.battleground", "Battleground: the following players are joining as group:"); ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); @@ -220,11 +240,10 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) if (!member) continue; // this should never happen - WorldPacket data; - - if (err <= 0) + if (err) { - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); + WorldPacket data; + sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, err); member->GetSession()->SendPacket(&data); continue; } @@ -232,65 +251,107 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) // add to queue uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType, 0); - member->GetSession()->SendPacket(&data); - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); + // add joined time data + member->AddBattlegroundQueueJoinTime(bgTypeId, ginfo->JoinTime); + + WorldPacket data; // send status packet (in queue) + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, member, queueSlot, STATUS_WAIT_QUEUE, avgTime, ginfo->JoinTime, ginfo->ArenaType); member->GetSession()->SendPacket(&data); TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName().c_str()); } TC_LOG_DEBUG("bg.battleground", "Battleground: group end"); } + sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); } void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPacket& /*recvData*/) { - TC_LOG_DEBUG("network", "WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message"); + TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEGROUND_PLAYER_POSITIONS Message"); Battleground* bg = _player->GetBattleground(); if (!bg) // can't be received if player not in battleground return; - uint32 flagCarrierCount = 0; - Player* allianceFlagCarrier = NULL; - Player* hordeFlagCarrier = NULL; + uint32 acount = 0; + uint32 hcount = 0; + Player* aplr = NULL; + Player* hplr = NULL; if (uint64 guid = bg->GetFlagPickerGUID(TEAM_ALLIANCE)) { - allianceFlagCarrier = ObjectAccessor::FindPlayer(guid); - if (allianceFlagCarrier) - ++flagCarrierCount; + aplr = ObjectAccessor::FindPlayer(guid); + if (aplr) + ++acount; } if (uint64 guid = bg->GetFlagPickerGUID(TEAM_HORDE)) { - hordeFlagCarrier = ObjectAccessor::FindPlayer(guid); - if (hordeFlagCarrier) - ++flagCarrierCount; + hplr = ObjectAccessor::FindPlayer(guid); + if (hplr) + ++hcount; } - WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, 4 + 4 + 16 * flagCarrierCount); - // Used to send several player positions (found used in AV) - data << 0; // CGBattlefieldInfo__m_numPlayerPositions - /* - for (CGBattlefieldInfo__m_numPlayerPositions) - data << guid << posx << posy; - */ - data << flagCarrierCount; - if (allianceFlagCarrier) + ObjectGuid aguid = aplr ? aplr->GetGUID() : 0; + ObjectGuid hguid = hplr ? hplr->GetGUID() : 0; + + WorldPacket data(SMSG_BATTLEFIELD_PLAYER_POSITIONS); + + data.WriteBits(acount, 22); + for (uint8 i = 0; i < acount; i++) + { + data.WriteBit(aguid[3]); + data.WriteBit(aguid[5]); + data.WriteBit(aguid[1]); + data.WriteBit(aguid[6]); + data.WriteBit(aguid[7]); + data.WriteBit(aguid[0]); + data.WriteBit(aguid[2]); + data.WriteBit(aguid[4]); + } + + data.WriteBits(hcount, 22); + for (uint8 i = 0; i < hcount; i++) + { + data.WriteBit(hguid[6]); + data.WriteBit(hguid[5]); + data.WriteBit(hguid[4]); + data.WriteBit(hguid[7]); + data.WriteBit(hguid[2]); + data.WriteBit(hguid[1]); + data.WriteBit(hguid[0]); + data.WriteBit(hguid[3]); + } + + data.FlushBits(); + + for (uint8 i = 0; i < hcount; i++) { - data << uint64(allianceFlagCarrier->GetGUID()); - data << float(allianceFlagCarrier->GetPositionX()); - data << float(allianceFlagCarrier->GetPositionY()); + data.WriteByteSeq(hguid[2]); + data.WriteByteSeq(hguid[1]); + data << float(hplr->GetPositionY()); + data.WriteByteSeq(hguid[5]); + data.WriteByteSeq(hguid[4]); + data.WriteByteSeq(hguid[7]); + data.WriteByteSeq(hguid[0]); + data.WriteByteSeq(hguid[6]); + data.WriteByteSeq(hguid[3]); + data << float(hplr->GetPositionX()); } - if (hordeFlagCarrier) + for (uint8 i = 0; i < acount; i++) { - data << uint64(hordeFlagCarrier->GetGUID()); - data << float(hordeFlagCarrier->GetPositionX()); - data << float(hordeFlagCarrier->GetPositionY()); + data.WriteByteSeq(aguid[6]); + data << float(aplr->GetPositionX()); + data.WriteByteSeq(aguid[5]); + data.WriteByteSeq(aguid[3]); + data << float(aplr->GetPositionY()); + data.WriteByteSeq(aguid[1]); + data.WriteByteSeq(aguid[7]); + data.WriteByteSeq(aguid[0]); + data.WriteByteSeq(aguid[2]); + data.WriteByteSeq(aguid[4]); } SendPacket(&data); @@ -298,7 +359,7 @@ void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPacket& /*recvDa void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recvData*/) { - TC_LOG_DEBUG("network", "WORLD: Recvd MSG_PVP_LOG_DATA Message"); + TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_PVP_LOG_DATA Message"); Battleground* bg = _player->GetBattleground(); if (!bg) @@ -312,22 +373,16 @@ void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recvData*/) bg->BuildPvPLogDataPacket(data); SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: Sent MSG_PVP_LOG_DATA Message"); + TC_LOG_DEBUG("network", "WORLD: Sent SMSG_PVP_LOG_DATA Message"); } -void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recvData) +void WorldSession::HandleBattlefieldListOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); uint32 bgTypeId; recvData >> bgTypeId; // id from DBC - uint8 fromWhere; - recvData >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) - - uint8 canGainXP; - recvData >> canGainXP; // players with locked xp have their own bg queue on retail - BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) { @@ -336,60 +391,87 @@ void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recvData) } WorldPacket data; - sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId), fromWhere); + sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId)); SendPacket(&data); } void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { - uint8 type; // arenatype if arena - uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 - uint32 bgTypeId_; // type id from dbc - uint16 unk; // 0x1F90 constant? - uint8 action; // enter battle 0x1, leave queue 0x0 + TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); + + uint32 time; + uint32 queueSlot; + uint32 unk; + uint8 action; // enter battle 0x1, leave queue 0x0 + ObjectGuid guid; + + recvData >> time; + recvData >> queueSlot; + recvData >> unk; + + guid[0] = recvData.ReadBit(); + guid[1] = recvData.ReadBit(); + guid[5] = recvData.ReadBit(); + guid[6] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + guid[4] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + guid[2] = recvData.ReadBit(); + + action = recvData.ReadBit(); + + recvData.ReadByteSeq(guid[1]); + recvData.ReadByteSeq(guid[3]); + recvData.ReadByteSeq(guid[5]); + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[2]); + recvData.ReadByteSeq(guid[6]); + recvData.ReadByteSeq(guid[4]); - recvData >> type >> unk2 >> bgTypeId_ >> unk >> action; - if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) + if (!_player->InBattlegroundQueue()) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Invalid BgType!", - GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Player not in queue!", + GetPlayerInfo().c_str(), queueSlot, unk, time, action); return; } - if (!_player->InBattlegroundQueue()) + BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(queueSlot); + if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player not in queue!", - GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Invalid queueSlot!", + GetPlayerInfo().c_str(), queueSlot, unk, time, action); return; } - //get GroupQueueInfo from BattlegroundQueue - BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); - BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, type); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); + //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player not in queue (No player Group Info)!", - GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Player not in queue (No player Group Info)!", + GetPlayerInfo().c_str(), queueSlot, unk, time, action); return; } // if action == 1, then instanceId is required if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Player is not invited to any bg!", - GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Player is not invited to any bg!", + GetPlayerInfo().c_str(), queueSlot, unk, time, action); return; } - Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); + BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(bgQueueTypeId); + // BGTemplateId returns BATTLEGROUND_AA when it is arena queue. + // Do instance id search as there is no AA bg instances. + Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId == BATTLEGROUND_AA ? BATTLEGROUND_TYPE_NONE : bgTypeId); if (!bg) { if (action) { - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u. Cant find BG with id %u!", - GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action, ginfo.IsInvitedToBGInstanceGUID); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u. Cant find BG with id %u!", + GetPlayerInfo().c_str(), queueSlot, unk, time, action, ginfo.IsInvitedToBGInstanceGUID); return; } @@ -401,8 +483,11 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) } } - TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s ArenaType: %u, Unk: %u, BgType: %u, Action: %u.", - GetPlayerInfo().c_str(), type, unk2, bgTypeId_, action); + TC_LOG_DEBUG("bg.battleground", "CMSG_BATTLEFIELD_PORT %s Slot: %u, Unk: %u, Time: %u, Action: %u.", + GetPlayerInfo().c_str(), queueSlot, unk, time, action); + + // get real bg type + bgTypeId = bg->GetTypeID(); // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); @@ -417,7 +502,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { //send bg command result to show nice message WorldPacket data2; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); + sBattlegroundMgr->BuildStatusFailedPacket(&data2, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); _player->GetSession()->SendPacket(&data2); action = 0; TC_LOG_DEBUG("bg.battleground", "Player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName().c_str(), _player->GetGUIDLow()); @@ -425,12 +510,12 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue if (_player->getLevel() > bg->GetMaxLevel()) { - TC_LOG_ERROR("network", "Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", + TC_LOG_DEBUG("network", "Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", _player->GetName().c_str(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); action = 0; } } - uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); + WorldPacket data; if (action) { @@ -453,7 +538,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) _player->CleanupAfterTaxiFlight(); } - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), ginfo.Team); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_IN_PROGRESS, _player->GetBattlegroundQueueJoinTime(bgTypeId), bg->GetElapsedTime(), bg->GetArenaType()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr @@ -476,9 +561,6 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) } else // leave queue { - if (bg->isArena() && bg->GetStatus() > STATUS_WAIT_QUEUE) - return; - // if player leaves rated arena match before match start, it is counted as he played but he lost if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) { @@ -490,25 +572,22 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) at->SaveToDB(); } } + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_NONE, _player->GetBattlegroundQueueJoinTime(bgTypeId), 0, 0); + SendPacket(&data); + _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!ginfo.ArenaType) sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); - SendPacket(&data); + TC_LOG_DEBUG("bg.battleground", "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName().c_str(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); } } -void WorldSession::HandleBattlefieldLeaveOpcode(WorldPacket& recvData) +void WorldSession::HandleBattlefieldLeaveOpcode(WorldPacket& /*recvData*/) { - TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message"); - - recvData.read_skip<uint8>(); // unk1 - recvData.read_skip<uint8>(); // unk2 - recvData.read_skip<uint32>(); // BattlegroundTypeId - recvData.read_skip<uint16>(); // unk3 + TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_LEAVE Message"); // not allow leave battleground in combat if (_player->IsInCombat()) @@ -522,7 +601,7 @@ void WorldSession::HandleBattlefieldLeaveOpcode(WorldPacket& recvData) void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) { // empty opcode - TC_LOG_DEBUG("network", "WORLD: Battleground status"); + TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_BATTLEFIELD_STATUS Message"); WorldPacket data; // we must update all queues here @@ -541,13 +620,14 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) //so i must use bg pointer to get that information if (bg && bg->GetArenaType() == arenaType) { - // this line is checked, i only don't know if GetStartTime is changing itself after bg end! + // this line is checked, i only don't know if GetElapsedTime() is changing itself after bg end! // send status in Battleground - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType, _player->GetBGTeam()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, GetPlayer(), i, STATUS_IN_PROGRESS, _player->GetBattlegroundQueueJoinTime(bgTypeId), bg->GetElapsedTime(), arenaType); SendPacket(&data); continue; } } + //we are sending update to player about queue - he can be invited there! //get GroupQueueInfo for queue status BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); @@ -559,9 +639,9 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); if (!bg) continue; - uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); + // send status invited to Battleground - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, GetPlayer(), i, STATUS_WAIT_JOIN, getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime), _player->GetBattlegroundQueueJoinTime(bgTypeId), arenaType); SendPacket(&data); } else @@ -577,7 +657,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId()); // send status in Battleground Queue - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, GetPlayer(), i, STATUS_WAIT_QUEUE, avgTime, _player->GetBattlegroundQueueJoinTime(bgTypeId), arenaType); SendPacket(&data); } } @@ -587,44 +667,18 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: CMSG_BATTLEMASTER_JOIN_ARENA"); - uint64 guid; // arena Battlemaster guid uint8 arenaslot; // 2v2, 3v3 or 5v5 - uint8 asGroup; // asGroup - uint8 isRated; // isRated - Group* grp = NULL; - recvData >> guid >> arenaslot >> asGroup >> isRated; + recvData >> arenaslot; // ignore if we already in BG or BG queue if (_player->InBattleground()) return; - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->IsBattleMaster()) // it's not battle master - return; - - uint8 arenatype = 0; uint32 arenaRating = 0; uint32 matchmakerRating = 0; - switch (arenaslot) - { - case 0: - arenatype = ARENA_TYPE_2v2; - break; - case 1: - arenatype = ARENA_TYPE_3v3; - break; - case 2: - arenatype = ARENA_TYPE_5v5; - break; - default: - TC_LOG_ERROR("network", "Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot); - return; - } + uint8 arenatype = ArenaTeam::GetTypeBySlot(arenaslot); //check existance Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_AA); @@ -646,108 +700,73 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) if (!bracketEntry) return; - GroupJoinBattlegroundResult err = ERR_GROUP_JOIN_BATTLEGROUND_FAIL; + GroupJoinBattlegroundResult err = ERR_BATTLEGROUND_NONE; - if (!asGroup) - { - // check if already in queue - if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) - //player is already in this queue - return; - // check if has free queue slots - if (!_player->HasFreeBattlegroundQueueId()) - return; - } - else + Group* grp = _player->GetGroup(); + // no group found, error + if (!grp) + return; + if (grp->GetLeaderGUID() != _player->GetGUID()) + return; + + uint32 ateamId = _player->GetArenaTeamId(arenaslot); + // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) + ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ateamId); + if (!at) { - grp = _player->GetGroup(); - // no group found, error - if (!grp) - return; - if (grp->GetLeaderGUID() != _player->GetGUID()) - return; - err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, arenatype, arenatype, isRated != 0, arenaslot); + _player->GetSession()->SendNotInArenaTeamPacket(arenatype); + return; } - uint32 ateamId = 0; + // get the team rating for queueing + arenaRating = at->GetRating(); + matchmakerRating = at->GetAverageMMR(grp); + // the arenateam id must match for everyone in the group + + if (arenaRating <= 0) + arenaRating = 1; + + BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); - if (isRated) + uint32 avgTime = 0; + GroupQueueInfo* ginfo = NULL; + + err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, arenatype, arenatype, true, arenaslot); + if (!err) { - ateamId = _player->GetArenaTeamId(arenaslot); - // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) - ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ateamId); - if (!at) - { - _player->GetSession()->SendNotInArenaTeamPacket(arenatype); - return; - } - // get the team rating for queueing - arenaRating = at->GetRating(); - matchmakerRating = at->GetAverageMMR(grp); - // the arenateam id must match for everyone in the group + TC_LOG_DEBUG("bg.battleground", "Battleground: arena team id %u, leader %s queued with matchmaker rating %u for type %u", _player->GetArenaTeamId(arenaslot), _player->GetName().c_str(), matchmakerRating, arenatype); - if (arenaRating <= 0) - arenaRating = 1; + ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, true, false, arenaRating, matchmakerRating, ateamId); + avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); } - BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); - if (asGroup) + for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { - uint32 avgTime = 0; + Player* member = itr->GetSource(); + if (!member) + continue; - if (err > 0) + if (err) { - TC_LOG_DEBUG("bg.battleground", "Battleground: arena join as group start"); - if (isRated) - { - TC_LOG_DEBUG("bg.battleground", "Battleground: arena team id %u, leader %s queued with matchmaker rating %u for type %u", _player->GetArenaTeamId(arenaslot), _player->GetName().c_str(), matchmakerRating, arenatype); - bg->SetRated(true); - } - else - bg->SetRated(false); - - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated != 0, false, arenaRating, matchmakerRating, ateamId); - avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + WorldPacket data; + sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, err); + member->GetSession()->SendPacket(&data); + continue; } - for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* member = itr->GetSource(); - if (!member) - continue; - - WorldPacket data; + // add to queue + uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); - if (err <= 0) - { - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - continue; - } + // add joined time data + member->AddBattlegroundQueueJoinTime(bgTypeId, ginfo->JoinTime); - // add to queue - uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); + WorldPacket data; // send status packet (in queue) + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, member, queueSlot, STATUS_WAIT_QUEUE, avgTime, ginfo->JoinTime, arenatype); + member->GetSession()->SendPacket(&data); - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype, 0); - member->GetSession()->SendPacket(&data); - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName().c_str()); - } + TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName().c_str()); } - else - { - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, arenatype, isRated != 0, false, arenaRating, matchmakerRating, ateamId); - uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); - WorldPacket data; - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype, 0); - SendPacket(&data); - TC_LOG_DEBUG("bg.battleground", "Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName().c_str()); - } sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); } @@ -767,3 +786,78 @@ void WorldSession::HandleReportPvPAFK(WorldPacket& recvData) reportedPlayer->ReportedAfkBy(_player); } + +void WorldSession::HandleRequestRatedBgInfo(WorldPacket & recvData) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_REQUEST_RATED_BG_INFO"); + + uint8 unk; + recvData >> unk; + + TC_LOG_DEBUG("bg.battleground", "WorldSession::HandleRequestRatedBgInfo: unk = %u", unk); + + /// @Todo: perfome research in this case + /// The unk fields are related to arenas + WorldPacket data(SMSG_RATED_BG_STATS, 72); + data << uint32(0); // BgWeeklyWins20vs20 + data << uint32(0); // BgWeeklyPlayed20vs20 + data << uint32(0); // BgWeeklyPlayed15vs15 + data << uint32(0); + data << uint32(0); // BgWeeklyWins10vs10 + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); // BgWeeklyWins15vs15 + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); // BgWeeklyPlayed10vs10 + data << uint32(0); + data << uint32(0); + + SendPacket(&data); +} + +void WorldSession::HandleRequestPvpOptions(WorldPacket& /*recvData*/) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_REQUEST_PVP_OPTIONS_ENABLED"); + + /// @Todo: perfome research in this case + WorldPacket data(SMSG_PVP_OPTIONS_ENABLED, 1); + data.WriteBit(1); + data.WriteBit(1); // WargamesEnabled + data.WriteBit(1); + data.WriteBit(1); // RatedBGsEnabled + data.WriteBit(1); // RatedArenasEnabled + + data.FlushBits(); + + SendPacket(&data); +} + +void WorldSession::HandleRequestPvpReward(WorldPacket& /*recvData*/) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_REQUEST_PVP_REWARDS"); + + _player->SendPvpRewards(); +} + +void WorldSession::HandleRequestRatedBgStats(WorldPacket& /*recvData*/) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_REQUEST_RATED_BG_STATS"); + + WorldPacket data(SMSG_BATTLEFIELD_RATED_INFO, 29); + data << uint32(0); // Reward + data << uint8(3); // unk + data << uint32(0); // unk + data << uint32(0); // unk + data << _player->GetCurrencyWeekCap(CURRENCY_TYPE_CONQUEST_META_RBG, true); + data << uint32(0); // unk + data << uint32(0); // unk + data << _player->GetCurrency(CURRENCY_TYPE_CONQUEST_POINTS, true); + + SendPacket(&data); +} diff --git a/src/server/game/Handlers/BattlefieldHandler.cpp b/src/server/game/Handlers/BattlefieldHandler.cpp index b0580681f91..632cf83cd8f 100644 --- a/src/server/game/Handlers/BattlefieldHandler.cpp +++ b/src/server/game/Handlers/BattlefieldHandler.cpp @@ -21,96 +21,223 @@ #include "Player.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "Object.h" #include "Battlefield.h" #include "BattlefieldMgr.h" /** - * @fn void WorldSession::SendBfInvitePlayerToWar(uint32 battleId, uint32 zoneId, uint32 acceptTime) + * @fn void WorldSession::SendBfInvitePlayerToWar(uint64 guid, uint32 zoneId, uint32 acceptTime) * * @brief This send to player windows for invite player to join the war. * - * @param battleId The BattleId of Bf + * @param guid The guid of Bf * @param zoneId The zone where the battle is (4197 for wg) * @param acceptTime Time in second that the player have for accept */ -void WorldSession::SendBfInvitePlayerToWar(uint32 battleId, uint32 zoneId, uint32 acceptTime) +void WorldSession::SendBfInvitePlayerToWar(uint64 guid, uint32 zoneId, uint32 acceptTime) { - WorldPacket data(SMSG_BATTLEFIELD_MGR_ENTRY_INVITE, 12); - data << uint32(battleId); - data << uint32(zoneId); - data << uint32(time(NULL) + acceptTime); + ObjectGuid guidBytes = guid; + + WorldPacket data(SMSG_BATTLEFIELD_MGR_ENTRY_INVITE, 16); + + data.WriteBit(guidBytes[5]); + data.WriteBit(guidBytes[3]); + data.WriteBit(guidBytes[7]); + data.WriteBit(guidBytes[2]); + data.WriteBit(guidBytes[6]); + data.WriteBit(guidBytes[4]); + data.WriteBit(guidBytes[1]); + data.WriteBit(guidBytes[0]); + + data.WriteByteSeq(guidBytes[6]); + data << uint32(zoneId); // Zone Id + data.WriteByteSeq(guidBytes[1]); + data.WriteByteSeq(guidBytes[3]); + data.WriteByteSeq(guidBytes[4]); + data.WriteByteSeq(guidBytes[2]); + data.WriteByteSeq(guidBytes[0]); + data << uint32(time(NULL) + acceptTime); // Invite lasts until + data.WriteByteSeq(guidBytes[7]); + data.WriteByteSeq(guidBytes[5]); SendPacket(&data); } /** - * @fn void WorldSession::SendBfInvitePlayerToQueue(uint32 battleId) + * @fn void WorldSession::SendBfInvitePlayerToQueue(uint64 guid) * * @brief This send invitation to player to join the queue. * - * @param battleId The BattleId of Bf + * @param guid The guid of Bf */ -void WorldSession::SendBfInvitePlayerToQueue(uint32 battleId) +void WorldSession::SendBfInvitePlayerToQueue(uint64 guid) { + ObjectGuid guidBytes = guid; + WorldPacket data(SMSG_BATTLEFIELD_MGR_QUEUE_INVITE, 5); - data << uint32(battleId); - data << uint8(1); // warmup ? used ? + + data.WriteBit(1); // unk + data.WriteBit(0); // Has Warmup + data.WriteBit(1); // unk + data.WriteBit(guidBytes[0]); + data.WriteBit(1); // unk + data.WriteBit(guidBytes[2]); + data.WriteBit(guidBytes[6]); + data.WriteBit(guidBytes[3]); + data.WriteBit(1); // unk + data.WriteBit(0); // unk + data.WriteBit(guidBytes[1]); + data.WriteBit(guidBytes[5]); + data.WriteBit(guidBytes[4]); + data.WriteBit(1); // unk + data.WriteBit(guidBytes[7]); + + data.FlushBits(); + + data.WriteByteSeq(guidBytes[2]); + data.WriteByteSeq(guidBytes[3]); + data.WriteByteSeq(guidBytes[6]); + data << uint8(1); // Warmup + data.WriteByteSeq(guidBytes[5]); + data.WriteByteSeq(guidBytes[0]); + data.WriteByteSeq(guidBytes[4]); + data.WriteByteSeq(guidBytes[1]); + data.WriteByteSeq(guidBytes[7]); SendPacket(&data); } /** - * @fn void WorldSession::SendBfQueueInviteResponse(uint32 battleId, uint32 zoneId, bool canQueue, bool full) + * @fn void WorldSession::SendBfQueueInviteResponse(uint64 guid, uint32 zoneId, bool canQueue, bool full) * * @brief This send packet for inform player that he join queue. * - * @param battleId The BattleId of Bf + * @param guid The guid of Bf * @param zoneId The zone where the battle is (4197 for wg) * @param canQueue if able to queue * @param full on log in is full */ -void WorldSession::SendBfQueueInviteResponse(uint32 battleId, uint32 zoneId, bool canQueue, bool full) +void WorldSession::SendBfQueueInviteResponse(uint64 guid, uint32 zoneId, bool canQueue, bool full) { - WorldPacket data(SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE, 11); - data << uint32(battleId); + const bool hasSecondGuid = false; + const bool warmup = true; + ObjectGuid guidBytes = guid; + + WorldPacket data(SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE, 16); + + data.WriteBit(guidBytes[1]); + data.WriteBit(guidBytes[6]); + data.WriteBit(guidBytes[5]); + data.WriteBit(guidBytes[7]); + data.WriteBit(full); // Logging In, VERIFYME + data.WriteBit(guidBytes[0]); + data.WriteBit(!hasSecondGuid); + data.WriteBit(guidBytes[4]); + + // if (hasSecondGuid) 7 3 0 4 2 6 1 5 + + data.WriteBit(guidBytes[3]); + data.WriteBit(guidBytes[2]); + + // if (hasSecondGuid) 2 5 3 0 4 6 1 7 + + data.FlushBits(); + + data << uint8(canQueue); // Accepted + + data.WriteByteSeq(guidBytes[1]); + data.WriteByteSeq(guidBytes[3]); + data.WriteByteSeq(guidBytes[6]); + data.WriteByteSeq(guidBytes[7]); + data.WriteByteSeq(guidBytes[0]); + + data << uint8(warmup); + + data.WriteByteSeq(guidBytes[2]); + data.WriteByteSeq(guidBytes[4]); + data.WriteByteSeq(guidBytes[5]); + data << uint32(zoneId); - data << uint8(canQueue ? 1 : 0); // Accepted // 0 you cannot queue wg // 1 you are queued - data << uint8(full ? 0 : 1); // Logging In // 0 wg full // 1 queue for upcoming - data << uint8(1); // Warmup + SendPacket(&data); } /** - * @fn void WorldSession::SendBfEntered(uint32 battleId) + * @fn void WorldSession::SendBfEntered(uint64 guid) * * @brief This is call when player accept to join war. * - * @param battleId The BattleId of Bf + * @param guid The guid of Bf */ -void WorldSession::SendBfEntered(uint32 battleId) +void WorldSession::SendBfEntered(uint64 guid) { - WorldPacket data(SMSG_BATTLEFIELD_MGR_ENTERED, 7); - data << uint32(battleId); - data << uint8(1); // unk - data << uint8(1); // unk - data << uint8(_player->isAFK() ? 1 : 0); // Clear AFK + uint8 isAFK = _player->isAFK() ? 1 : 0; + ObjectGuid guidBytes = guid; + + WorldPacket data(SMSG_BATTLEFIELD_MGR_ENTERED, 11); + + data.WriteBit(0); // unk + data.WriteBit(isAFK); // Clear AFK + data.WriteBit(guidBytes[1]); + data.WriteBit(guidBytes[4]); + data.WriteBit(guidBytes[5]); + data.WriteBit(guidBytes[0]); + data.WriteBit(guidBytes[3]); + data.WriteBit(0); // unk + data.WriteBit(guidBytes[6]); + data.WriteBit(guidBytes[7]); + data.WriteBit(guidBytes[2]); + + data.FlushBits(); + + data.WriteByteSeq(guidBytes[5]); + data.WriteByteSeq(guidBytes[3]); + data.WriteByteSeq(guidBytes[0]); + data.WriteByteSeq(guidBytes[4]); + data.WriteByteSeq(guidBytes[1]); + data.WriteByteSeq(guidBytes[7]); + data.WriteByteSeq(guidBytes[2]); + data.WriteByteSeq(guidBytes[6]); + SendPacket(&data); } /** - * @fn void WorldSession::SendBfLeaveMessage(uint32 battleId, BFLeaveReason reason) + * @fn void WorldSession::SendBfLeaveMessage(uint64 guid, BFLeaveReason reason) * * @brief This is call when player leave battlefield zone. * - * @param battleId The BattleId of Bf + * @param guid The guid of Bf * @param reason Reason why player left battlefield */ -void WorldSession::SendBfLeaveMessage(uint32 battleId, BFLeaveReason reason /*= BF_LEAVE_REASON_EXITED*/) +void WorldSession::SendBfLeaveMessage(uint64 guid, BFLeaveReason reason /*= BF_LEAVE_REASON_EXITED*/) { - WorldPacket data(SMSG_BATTLEFIELD_MGR_EJECTED, 7); - data << uint32(battleId); - data << uint8(reason); // byte Reason - data << uint8(2); // byte BattleStatus - data << uint8(0); // bool Relocated + ObjectGuid guidBytes = guid; + + WorldPacket data(SMSG_BATTLEFIELD_MGR_EJECTED, 11); + + data.WriteBit(guidBytes[2]); + data.WriteBit(guidBytes[5]); + data.WriteBit(guidBytes[1]); + data.WriteBit(guidBytes[0]); + data.WriteBit(guidBytes[3]); + data.WriteBit(guidBytes[6]); + data.WriteBit(0); // Relocated + data.WriteBit(guidBytes[7]); + data.WriteBit(guidBytes[4]); + + data.FlushBits(); + + data << uint8(2); // BattleStatus + data.WriteByteSeq(guidBytes[1]); + data.WriteByteSeq(guidBytes[7]); + data.WriteByteSeq(guidBytes[4]); + data.WriteByteSeq(guidBytes[2]); + data.WriteByteSeq(guidBytes[3]); + data << uint8(reason); // Reason + data.WriteByteSeq(guidBytes[6]); + data.WriteByteSeq(guidBytes[0]); + data.WriteByteSeq(guidBytes[5]); + SendPacket(&data); } @@ -121,14 +248,31 @@ void WorldSession::SendBfLeaveMessage(uint32 battleId, BFLeaveReason reason /*= */ void WorldSession::HandleBfQueueInviteResponse(WorldPacket& recvData) { - uint32 battleId; uint8 accepted; + ObjectGuid guid; + + guid[2] = recvData.ReadBit(); + guid[0] = recvData.ReadBit(); + guid[4] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + guid[5] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + accepted = recvData.ReadBit(); + guid[1] = recvData.ReadBit(); + guid[6] = recvData.ReadBit(); - recvData >> battleId >> accepted; + recvData.ReadByteSeq(guid[1]); + recvData.ReadByteSeq(guid[3]); + recvData.ReadByteSeq(guid[2]); + recvData.ReadByteSeq(guid[4]); + recvData.ReadByteSeq(guid[6]); + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[5]); - TC_LOG_DEBUG("misc", "HandleBfQueueInviteResponse: BattleID:%u Accepted:%u", battleId, accepted); + TC_LOG_ERROR("misc", "HandleQueueInviteResponse: GUID: " UI64FMTD ", accepted: %u", uint64(guid), accepted); - Battlefield* bf = sBattlefieldMgr->GetBattlefieldByBattleId(battleId); + Battlefield* bf = sBattlefieldMgr->GetBattlefieldByGUID(guid); if (!bf) return; @@ -143,14 +287,31 @@ void WorldSession::HandleBfQueueInviteResponse(WorldPacket& recvData) */ void WorldSession::HandleBfEntryInviteResponse(WorldPacket& recvData) { - uint32 battleId; uint8 accepted; + ObjectGuid guid; - recvData >> battleId >> accepted; + guid[6] = recvData.ReadBit(); + guid[1] = recvData.ReadBit(); + accepted = recvData.ReadBit(); + guid[5] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + guid[2] = recvData.ReadBit(); + guid[0] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + guid[4] = recvData.ReadBit(); - TC_LOG_DEBUG("misc", "HandleBfEntryInviteResponse: battleId: %u, accepted: %u", battleId, accepted); + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[3]); + recvData.ReadByteSeq(guid[4]); + recvData.ReadByteSeq(guid[2]); + recvData.ReadByteSeq(guid[1]); + recvData.ReadByteSeq(guid[6]); + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[5]); - Battlefield* bf = sBattlefieldMgr->GetBattlefieldByBattleId(battleId); + TC_LOG_ERROR("misc", "HandleBattlefieldInviteResponse: GUID: " UI64FMTD ", accepted: %u", uint64(guid), accepted); + + Battlefield* bf = sBattlefieldMgr->GetBattlefieldByGUID(guid); if (!bf) return; @@ -173,13 +334,29 @@ void WorldSession::HandleBfEntryInviteResponse(WorldPacket& recvData) */ void WorldSession::HandleBfExitRequest(WorldPacket& recvData) { - uint32 battleId; + ObjectGuid guid; + + guid[2] = recvData.ReadBit(); + guid[0] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + guid[4] = recvData.ReadBit(); + guid[5] = recvData.ReadBit(); + guid[6] = recvData.ReadBit(); + guid[1] = recvData.ReadBit(); - recvData >> battleId; + recvData.ReadByteSeq(guid[5]); + recvData.ReadByteSeq(guid[2]); + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[1]); + recvData.ReadByteSeq(guid[4]); + recvData.ReadByteSeq(guid[3]); + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[6]); - TC_LOG_DEBUG("misc", "HandleBfExitRequest: battleId: %u ", battleId); + TC_LOG_ERROR("misc", "HandleBfExitRequest: GUID: " UI64FMTD, uint64(guid)); - Battlefield* bf = sBattlefieldMgr->GetBattlefieldByBattleId(battleId); + Battlefield* bf = sBattlefieldMgr->GetBattlefieldByGUID(guid); if (!bf) return; diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index dd654fb3ad0..a7de4491a85 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -90,6 +90,10 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/) data.AppendPackedTime(calendarEvent->GetEventTime()); data << uint32(calendarEvent->GetFlags()); data << int32(calendarEvent->GetDungeonId()); + + Guild* guild = sGuildMgr->GetGuildById(calendarEvent->GetGuildId()); + data << uint64(guild ? guild->GetGUID() : 0); + data.appendPackGUID(calendarEvent->GetCreatorGUID()); } @@ -671,10 +675,11 @@ void WorldSession::HandleCalendarComplain(WorldPacket& recvData) uint64 guid = _player->GetGUID(); uint64 eventId; uint64 complainGUID; + uint64 inviteId; - recvData >> eventId >> complainGUID; + recvData >> complainGUID >> eventId >> inviteId; TC_LOG_DEBUG("network", "CMSG_CALENDAR_COMPLAIN [" UI64FMTD "] EventId [" - UI64FMTD "] guid [" UI64FMTD "]", guid, eventId, complainGUID); + UI64FMTD "] guid [" UI64FMTD "] InviteId [" UI64FMTD "]", guid, eventId, complainGUID, inviteId); // what to do with complains? } diff --git a/src/server/game/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp index c95eadc7d90..0ab5a8ab811 100644 --- a/src/server/game/Handlers/ChannelHandler.cpp +++ b/src/server/game/Handlers/ChannelHandler.cpp @@ -19,14 +19,21 @@ #include "ObjectMgr.h" // for normalizePlayerName #include "ChannelMgr.h" #include "Player.h" +#include "WorldSession.h" void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) { uint32 channelId; - uint8 unknown1, unknown2; + uint32 channelLength, passLength; std::string channelName, password; - recvPacket >> channelId >> unknown1 >> unknown2 >> channelName >> password; + recvPacket >> channelId; + uint8 unknown1 = recvPacket.ReadBit(); // unknowns + uint8 unknown2 = recvPacket.ReadBit(); + channelLength = recvPacket.ReadBits(8); + passLength = recvPacket.ReadBits(8); + channelName = recvPacket.ReadString(channelLength); + password = recvPacket.ReadString(passLength); TC_LOG_DEBUG("chat.system", "CMSG_JOIN_CHANNEL %s Channel: %u, unk1: %u, unk2: %u, channel: %s, password: %s", GetPlayerInfo().c_str(), channelId, unknown1, unknown2, channelName.c_str(), password.c_str()); @@ -57,7 +64,9 @@ void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket) { uint32 unk; std::string channelName; - recvPacket >> unk >> channelName; + recvPacket >> unk; // channel id? + uint32 length = recvPacket.ReadBits(8); + channelName = recvPacket.ReadString(length); TC_LOG_DEBUG("chat.system", "CMSG_LEAVE_CHANNEL %s Channel: %s, unk1: %u", GetPlayerInfo().c_str(), channelName.c_str(), unk); @@ -75,8 +84,8 @@ void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket) void WorldSession::HandleChannelList(WorldPacket& recvPacket) { - std::string channelName; - recvPacket >> channelName; + uint32 length = recvPacket.ReadBits(8); + std::string channelName = recvPacket.ReadString(length); TC_LOG_DEBUG("chat.system", "%s %s Channel: %s", recvPacket.GetOpcode() == CMSG_CHANNEL_DISPLAY_LIST ? "CMSG_CHANNEL_DISPLAY_LIST" : "CMSG_CHANNEL_LIST", @@ -89,8 +98,11 @@ void WorldSession::HandleChannelList(WorldPacket& recvPacket) void WorldSession::HandleChannelPassword(WorldPacket& recvPacket) { - std::string channelName, password; - recvPacket >> channelName >> password; + uint32 nameLength = recvPacket.ReadBits(8); + uint32 passLength = recvPacket.ReadBits(7); + + std::string channelName = recvPacket.ReadString(nameLength); + std::string password = recvPacket.ReadString(passLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_PASSWORD %s Channel: %s, Password: %s", GetPlayerInfo().c_str(), channelName.c_str(), password.c_str()); @@ -102,8 +114,11 @@ void WorldSession::HandleChannelPassword(WorldPacket& recvPacket) void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket) { - std::string channelName, targetName; - recvPacket >> channelName >> targetName; + uint32 channelLength = recvPacket.ReadBits(8); + uint32 nameLength = recvPacket.ReadBits(7); + + std::string targetName = recvPacket.ReadString(nameLength); + std::string channelName = recvPacket.ReadString(channelLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_SET_OWNER %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -118,8 +133,8 @@ void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket) void WorldSession::HandleChannelOwner(WorldPacket& recvPacket) { - std::string channelName; - recvPacket >> channelName; + uint32 length = recvPacket.ReadBits(8); + std::string channelName = recvPacket.ReadString(length); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_OWNER %s Channel: %s", GetPlayerInfo().c_str(), channelName.c_str()); @@ -131,8 +146,11 @@ void WorldSession::HandleChannelOwner(WorldPacket& recvPacket) void WorldSession::HandleChannelModerator(WorldPacket& recvPacket) { - std::string channelName, targetName; - recvPacket >> channelName >> targetName; + uint32 channelLength = recvPacket.ReadBits(8); + uint32 nameLength = recvPacket.ReadBits(7); + + std::string targetName = recvPacket.ReadString(nameLength); + std::string channelName = recvPacket.ReadString(channelLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_MODERATOR %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -147,8 +165,11 @@ void WorldSession::HandleChannelModerator(WorldPacket& recvPacket) void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket) { - std::string channelName, targetName; - recvPacket >> channelName >> targetName; + uint32 nameLength = recvPacket.ReadBits(7); + uint32 channelLength = recvPacket.ReadBits(8); + + std::string channelName = recvPacket.ReadString(channelLength); + std::string targetName = recvPacket.ReadString(nameLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_UNMODERATOR %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -163,8 +184,11 @@ void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket) void WorldSession::HandleChannelMute(WorldPacket& recvPacket) { - std::string channelName, targetName; - recvPacket >> channelName >> targetName; + uint32 channelLength = recvPacket.ReadBits(8); + uint32 nameLength = recvPacket.ReadBits(7); + + std::string channelName = recvPacket.ReadString(channelLength); + std::string targetName = recvPacket.ReadString(nameLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_MUTE %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -179,8 +203,11 @@ void WorldSession::HandleChannelMute(WorldPacket& recvPacket) void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket) { - std::string channelName, targetName; - recvPacket >> channelName >> targetName; + uint32 nameLength = recvPacket.ReadBits(8); + uint32 channelLength = recvPacket.ReadBits(7); + + std::string targetName = recvPacket.ReadString(nameLength); + std::string channelName = recvPacket.ReadString(channelLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_UNMUTE %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -195,8 +222,11 @@ void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket) void WorldSession::HandleChannelInvite(WorldPacket& recvPacket) { - std::string channelName, targetName; - recvPacket >> channelName >> targetName; + uint32 nameLength = recvPacket.ReadBits(7); + uint32 channelLength = recvPacket.ReadBits(8); + + std::string targetName = recvPacket.ReadString(nameLength); + std::string channelName = recvPacket.ReadString(channelLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_INVITE %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -211,8 +241,11 @@ void WorldSession::HandleChannelInvite(WorldPacket& recvPacket) void WorldSession::HandleChannelKick(WorldPacket& recvPacket) { - std::string channelName, targetName; - recvPacket >> channelName >> targetName; + uint32 channelLength = recvPacket.ReadBits(8); + uint32 nameLength = recvPacket.ReadBits(7); + + std::string channelName = recvPacket.ReadString(channelLength); + std::string targetName = recvPacket.ReadString(nameLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_KICK %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -227,8 +260,14 @@ void WorldSession::HandleChannelKick(WorldPacket& recvPacket) void WorldSession::HandleChannelBan(WorldPacket& recvPacket) { + uint32 channelLength, nameLength; std::string channelName, targetName; - recvPacket >> channelName >> targetName; + + channelLength = recvPacket.ReadBits(8); + nameLength = recvPacket.ReadBits(7); + + targetName = recvPacket.ReadString(nameLength); + channelName = recvPacket.ReadString(channelLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_BAN %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -243,8 +282,11 @@ void WorldSession::HandleChannelBan(WorldPacket& recvPacket) void WorldSession::HandleChannelUnban(WorldPacket& recvPacket) { - std::string channelName, targetName; - recvPacket >> channelName >> targetName; + uint32 channelLength = recvPacket.ReadBits(7); + uint32 nameLength = recvPacket.ReadBits(8); + + std::string targetName = recvPacket.ReadString(nameLength); + std::string channelName = recvPacket.ReadString(channelLength); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_UNBAN %s Channel: %s, Target: %s", GetPlayerInfo().c_str(), channelName.c_str(), targetName.c_str()); @@ -259,8 +301,8 @@ void WorldSession::HandleChannelUnban(WorldPacket& recvPacket) void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket) { - std::string channelName; - recvPacket >> channelName; + uint32 length = recvPacket.ReadBits(8); + std::string channelName = recvPacket.ReadString(length); TC_LOG_DEBUG("chat.system", "CMSG_CHANNEL_ANNOUNCEMENTS %s Channel: %s", GetPlayerInfo().c_str(), channelName.c_str()); @@ -300,7 +342,7 @@ void WorldSession::HandleGetChannelMemberCount(WorldPacket &recvPacket) } } -void WorldSession::HandleSetChannelWatch(WorldPacket &recvPacket) +void WorldSession::HandleSetChannelWatch(WorldPacket& recvPacket) { std::string channelName; recvPacket >> channelName; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 4d52eab61d6..422e5ce206b 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -26,6 +26,7 @@ #include "DatabaseEnv.h" #include "Group.h" #include "Guild.h" +#include "GuildFinderMgr.h" #include "GuildMgr.h" #include "Language.h" #include "LFGMgr.h" @@ -47,7 +48,6 @@ #include "WorldPacket.h" #include "WorldSession.h" - class LoginQueryHolder : public SQLQueryHolder { private: @@ -116,6 +116,10 @@ bool LoginQueryHolder::Initialize() stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INVENTORY, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_VOID_STORAGE); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS); stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACTIONS, stmt); @@ -168,6 +172,10 @@ bool LoginQueryHolder::Initialize() stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUF_PROFILES); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BGDATA); stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BG_DATA, stmt); @@ -204,39 +212,56 @@ bool LoginQueryHolder::Initialize() stmt->setUInt32(0, m_accountId); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_CURRENCY); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CURRENCY, stmt); + return res; } void WorldSession::HandleCharEnum(PreparedQueryResult result) { - WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size + uint32 charCount = 0; + ByteBuffer bitBuffer; + ByteBuffer dataBuffer; - uint8 num = 0; - - data << num; - - _legitCharacters.clear(); + bitBuffer.WriteBits(0, 23); + bitBuffer.WriteBit(1); if (result) { + _legitCharacters.clear(); + + charCount = uint32(result->GetRowCount()); + bitBuffer.reserve(24 * charCount / 8); + dataBuffer.reserve(charCount * 381); + + bitBuffer.WriteBits(charCount, 17); + do { - uint32 guidlow = (*result)[0].GetUInt32(); - TC_LOG_INFO("network", "Loading char guid %u from account %u.", guidlow, GetAccountId()); - if (Player::BuildEnumData(result, &data)) - { - // Do not allow banned characters to log in - if (!(*result)[20].GetUInt32()) - _legitCharacters.insert(guidlow); + uint32 guidLow = (*result)[0].GetUInt32(); - if (!sWorld->HasCharacterNameData(guidlow)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. - sWorld->AddCharacterNameData(guidlow, (*result)[1].GetString(), (*result)[4].GetUInt8(), (*result)[2].GetUInt8(), (*result)[3].GetUInt8(), (*result)[7].GetUInt8()); - ++num; - } - } - while (result->NextRow()); + TC_LOG_INFO("network", "Loading char guid %u from account %u.", guidLow, GetAccountId()); + + Player::BuildEnumData(result, &dataBuffer, &bitBuffer); + + // Do not allow banned characters to log in + if (!(*result)[20].GetUInt32()) + _legitCharacters.insert(guidLow); + + if (!sWorld->HasCharacterNameData(guidLow)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. + sWorld->AddCharacterNameData(guidLow, (*result)[1].GetString(), (*result)[4].GetUInt8(), (*result)[2].GetUInt8(), (*result)[3].GetUInt8(), (*result)[7].GetUInt8()); + } while (result->NextRow()); + + bitBuffer.FlushBits(); } + else + bitBuffer.WriteBits(0, 17); - data.put<uint8>(0, num); + WorldPacket data(SMSG_CHAR_ENUM, 7 + bitBuffer.size() + dataBuffer.size()); + data.append(bitBuffer); + if (charCount) + data.append(dataBuffer); SendPacket(&data); } @@ -762,6 +787,7 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData) sLog->outCharDump(dump.c_str(), accountId, GUID_LOPART(guid), name.c_str()); } + sGuildFinderMgr->RemoveAllMembershipRequestsFromPlayer(guid); sCalendarMgr->RemoveAllPlayerEventsAndInvites(guid); Player::DeleteFromDB(guid, accountId); @@ -780,11 +806,28 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData) } m_playerLoading = true; - uint64 playerGuid = 0; + ObjectGuid playerGuid; TC_LOG_DEBUG("network", "WORLD: Recvd Player Logon Message"); - - recvData >> playerGuid; + playerGuid[2] = recvData.ReadBit(); + playerGuid[3] = recvData.ReadBit(); + playerGuid[0] = recvData.ReadBit(); + playerGuid[6] = recvData.ReadBit(); + playerGuid[4] = recvData.ReadBit(); + playerGuid[5] = recvData.ReadBit(); + playerGuid[1] = recvData.ReadBit(); + playerGuid[7] = recvData.ReadBit(); + + recvData.ReadByteSeq(playerGuid[2]); + recvData.ReadByteSeq(playerGuid[7]); + recvData.ReadByteSeq(playerGuid[0]); + recvData.ReadByteSeq(playerGuid[3]); + recvData.ReadByteSeq(playerGuid[5]); + recvData.ReadByteSeq(playerGuid[6]); + recvData.ReadByteSeq(playerGuid[1]); + recvData.ReadByteSeq(playerGuid[4]); + + TC_LOG_DEBUG("network", "Character (Guid: %u) logging in", GUID_LOPART(playerGuid)); if (!IsLegitCharacterForAccount(GUID_LOPART(playerGuid))) { @@ -804,6 +847,17 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData) _charLoginCallback = CharacterDatabase.DelayQueryHolder((SQLQueryHolder*)holder); } +void WorldSession::HandleLoadScreenOpcode(WorldPacket& recvPacket) +{ + TC_LOG_INFO("misc", "WORLD: Recvd CMSG_LOAD_SCREEN"); + uint32 mapID; + + recvPacket >> mapID; + recvPacket.ReadBit(); + + // TODO: Do something with this packet +} + void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) { uint64 playerGuid = holder->GetGuid(); @@ -838,9 +892,34 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) LoadAccountData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA), PER_CHARACTER_CACHE_MASK); SendAccountDataTimes(PER_CHARACTER_CACHE_MASK); - data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0 + bool featureBit4 = true; + data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 7); // checked in 4.2.2 data << uint8(2); // unknown value - data << uint8(0); // enable(1)/disable(0) voice chat interface in client + data << uint32(1); + data << uint32(1); + data << uint32(2); + data << uint32(0); + data.WriteBit(1); + data.WriteBit(1); + data.WriteBit(0); + data.WriteBit(featureBit4); + data.WriteBit(0); + data.WriteBit(0); + data.FlushBits(); + if (featureBit4) + { + data << uint32(1); + data << uint32(0); + data << uint32(10); + data << uint32(60); + } + + //if (featureBit5) + //{ + // data << uint32(0); + // data << uint32(0); + // data << uint32(0); + //} SendPacket(&data); // Send MOTD @@ -887,28 +966,30 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) Field* fields = resultGuild->Fetch(); pCurrChar->SetInGuild(fields[0].GetUInt32()); pCurrChar->SetRank(fields[1].GetUInt8()); + if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId())) + pCurrChar->SetGuildLevel(guild->GetLevel()); } else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership { pCurrChar->SetInGuild(0); pCurrChar->SetRank(0); + pCurrChar->SetGuildLevel(0); } - if (pCurrChar->GetGuildId() != 0) + data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4); + data << uint64(0); + SendPacket(&data); + + data.Initialize(SMSG_HOTFIX_INFO); + HotfixData const& hotfix = sObjectMgr->GetHotfixData(); + data.WriteBits(hotfix.size(), 22); + data.FlushBits(); + for (uint32 i = 0; i < hotfix.size(); ++i) { - if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId())) - guild->SendLoginInfo(this); - else - { - // remove wrong guild data - TC_LOG_ERROR("network", "Player %s (GUID: %u) marked as member of not existing guild (id: %u), removing guild membership for player.", pCurrChar->GetName().c_str(), pCurrChar->GetGUIDLow(), pCurrChar->GetGuildId()); - pCurrChar->SetInGuild(0); - } + data << uint32(hotfix[i].Type); + data << uint32(hotfix[i].Timestamp); + data << uint32(hotfix[i].Entry); } - - data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4); - data << uint32(0); - data << uint32(0); SendPacket(&data); pCurrChar->SendInitialPacketsBeforeAddToMap(); @@ -933,7 +1014,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) if (!pCurrChar->GetMap()->AddPlayerToMap(pCurrChar) || !pCurrChar->CheckInstanceLoginValid()) { - AreaTrigger const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId()); + AreaTriggerStruct const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId()); if (at) pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation()); else @@ -943,18 +1024,26 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) sObjectAccessor->AddObject(pCurrChar); //TC_LOG_DEBUG("Player %s added to Map.", pCurrChar->GetName().c_str()); + if (pCurrChar->GetGuildId() != 0) + { + if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId())) + guild->SendLoginInfo(this); + else + { + // remove wrong guild data + TC_LOG_ERROR("misc", "Player %s (GUID: %u) marked as member of not existing guild (id: %u), removing guild membership for player.", pCurrChar->GetName().c_str(), pCurrChar->GetGUIDLow(), pCurrChar->GetGuildId()); + pCurrChar->SetInGuild(0); + } + } + pCurrChar->SendInitialPacketsAfterAddToMap(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ONLINE); - stmt->setUInt32(0, pCurrChar->GetGUIDLow()); - CharacterDatabase.Execute(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE); - stmt->setUInt32(0, GetAccountId()); - LoginDatabase.Execute(stmt); pCurrChar->SetInGameTime(getMSTime()); @@ -977,11 +1066,13 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) if (pCurrChar->m_deathState != ALIVE) { // not blizz like, we must correctly save and load player instead... - if (pCurrChar->getRace() == RACE_NIGHTELF) + if (pCurrChar->getRace() == RACE_NIGHTELF && !pCurrChar->HasAura(20584)) pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) - pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) - pCurrChar->SetMovement(MOVE_WATER_WALK); + if (!pCurrChar->HasAura(8326)) + pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) + + pCurrChar->SetWaterWalking(true); } pCurrChar->ContinueTaxiFlight(); @@ -1016,8 +1107,14 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) bool firstLogin = pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST); if (firstLogin) + { pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); + PlayerInfo const* info = sObjectMgr->GetPlayerInfo(pCurrChar->getRace(), pCurrChar->getClass()); + for (uint32 spellId : info->castSpells) + pCurrChar->CastSpell(pCurrChar, spellId, true); + } + // show time before shutdown if shutdown planned. if (sWorld->IsShuttingDown()) sWorld->ShutdownMsg(true, pCurrChar); @@ -1081,13 +1178,13 @@ void WorldSession::HandleTutorialFlag(WorldPacket& recvData) SetTutorialInt(index, flag); } -void WorldSession::HandleTutorialClear(WorldPacket & /*recvData*/) +void WorldSession::HandleTutorialClear(WorldPacket& /*recvData*/) { for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) SetTutorialInt(i, 0xFFFFFFFF); } -void WorldSession::HandleTutorialReset(WorldPacket & /*recvData*/) +void WorldSession::HandleTutorialReset(WorldPacket& /*recvData*/) { for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) SetTutorialInt(i, 0x00000000); @@ -1233,7 +1330,6 @@ void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recvData) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); - data << uint64(guid); SendPacket(&data); return; } @@ -1243,7 +1339,6 @@ void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recvData) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); - data << uint64(guid); SendPacket(&data); return; } @@ -1252,7 +1347,6 @@ void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recvData) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); - data << uint64(guid); SendPacket(&data); return; } @@ -1266,7 +1360,6 @@ void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recvData) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); - data << uint64(guid); SendPacket(&data); return; } @@ -1278,7 +1371,6 @@ void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recvData) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); - data << uint64(guid); SendPacket(&data); return; } @@ -1288,7 +1380,6 @@ void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recvData) { WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); data << uint32(1); - data << uint64(guid); SendPacket(&data); return; } @@ -1361,8 +1452,8 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData) // 0 - ok // 1, 3 - not enough money - // 2 - you have to seat on barber chair - if (!_player->HasEnoughMoney(cost)) + // 2 - you have to sit on barber chair + if (!_player->HasEnoughMoney((uint64)cost)) { WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); data << uint32(1); // no money @@ -1376,7 +1467,7 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData) SendPacket(&data); } - _player->ModifyMoney(-int32(cost)); // it isn't free + _player->ModifyMoney(-int64(cost)); // it isn't free _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, cost); _player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id)); @@ -1401,7 +1492,7 @@ void WorldSession::HandleRemoveGlyph(WorldPacket& recvData) return; } - if (uint32 glyph = _player->GetGlyph(slot)) + if (uint32 glyph = _player->GetGlyph(_player->GetActiveSpec(), slot)) { if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph)) { @@ -1433,7 +1524,6 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData) recvData >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AT_LOGIN); - stmt->setUInt32(0, GUID_LOPART(guid)); // TODO: Make async with callback PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -1537,7 +1627,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData) SendPacket(&data); } -void WorldSession::HandleEquipmentSetSave(WorldPacket &recvData) +void WorldSession::HandleEquipmentSetSave(WorldPacket& recvData) { TC_LOG_DEBUG("network", "CMSG_EQUIPMENT_SET_SAVE"); @@ -1599,7 +1689,7 @@ void WorldSession::HandleEquipmentSetDelete(WorldPacket &recvData) _player->DeleteEquipmentSet(setGuid); } -void WorldSession::HandleEquipmentSetUse(WorldPacket &recvData) +void WorldSession::HandleEquipmentSetUse(WorldPacket& recvData) { TC_LOG_DEBUG("network", "CMSG_EQUIPMENT_SET_USE"); @@ -1807,6 +1897,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) case RACE_UNDEAD_PLAYER: case RACE_TROLL: case RACE_BLOODELF: + case RACE_GOBLIN: team = TEAM_HORDE; break; default: @@ -1851,6 +1942,9 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) case RACE_NIGHTELF: stmt->setUInt16(1, 113); break; + case RACE_WORGEN: + stmt->setUInt16(1, 791); + break; case RACE_UNDEAD_PLAYER: stmt->setUInt16(1, 673); break; @@ -1863,6 +1957,9 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) case RACE_BLOODELF: stmt->setUInt16(1, 137); break; + case RACE_GOBLIN: + stmt->setUInt16(1, 792); + break; } trans->Append(stmt); @@ -2203,3 +2300,88 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) data << uint8(race); SendPacket(&data); } + +void WorldSession::HandleRandomizeCharNameOpcode(WorldPacket& recvData) +{ + uint8 gender, race; + + recvData >> race; + recvData >> gender; + + if (!Player::IsValidRace(race)) + { + TC_LOG_ERROR("misc", "Invalid race (%u) sent by accountId: %u", race, GetAccountId()); + return; + } + + if (!Player::IsValidGender(gender)) + { + TC_LOG_ERROR("misc", "Invalid gender (%u) sent by accountId: %u", gender, GetAccountId()); + return; + } + + std::string const* name = GetRandomCharacterName(race, gender); + WorldPacket data(SMSG_RANDOMIZE_CHAR_NAME, 10); + data.WriteBit(0); // unk + data.WriteBits(name->size(), 7); + data.WriteString(*name); + SendPacket(&data); +} + +void WorldSession::HandleReorderCharacters(WorldPacket& recvData) +{ + uint32 charactersCount = recvData.ReadBits(10); + + std::vector<ObjectGuid> guids(charactersCount); + uint8 position; + + for (uint8 i = 0; i < charactersCount; ++i) + { + guids[i][1] = recvData.ReadBit(); + guids[i][4] = recvData.ReadBit(); + guids[i][5] = recvData.ReadBit(); + guids[i][3] = recvData.ReadBit(); + guids[i][0] = recvData.ReadBit(); + guids[i][7] = recvData.ReadBit(); + guids[i][6] = recvData.ReadBit(); + guids[i][2] = recvData.ReadBit(); + } + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + for (uint8 i = 0; i < charactersCount; ++i) + { + recvData.ReadByteSeq(guids[i][6]); + recvData.ReadByteSeq(guids[i][5]); + recvData.ReadByteSeq(guids[i][1]); + recvData.ReadByteSeq(guids[i][4]); + recvData.ReadByteSeq(guids[i][0]); + recvData.ReadByteSeq(guids[i][3]); + + recvData >> position; + + recvData.ReadByteSeq(guids[i][2]); + recvData.ReadByteSeq(guids[i][7]); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_LIST_SLOT); + stmt->setUInt8(0, position); + stmt->setUInt32(1, GUID_LOPART(guids[i])); + trans->Append(stmt); + } + + CharacterDatabase.CommitTransaction(trans); +} + +void WorldSession::HandleOpeningCinematic(WorldPacket& /*recvData*/) +{ + // Only players that has not yet gained any experience can use this + if (_player->GetUInt32Value(PLAYER_XP)) + return; + + if (ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(_player->getClass())) + { + if (classEntry->CinematicSequence) + _player->SendCinematicStart(classEntry->CinematicSequence); + else if (ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(_player->getRace())) + _player->SendCinematicStart(raceEntry->CinematicSequence); + } +} diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index eccf7a6fd38..422d0d9c7d2 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -42,133 +42,185 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) { - uint32 type; + uint32 type = 0; uint32 lang; - recvData >> type; - recvData >> lang; - - if (type >= MAX_CHAT_MSG_TYPE) + switch (recvData.GetOpcode()) { - TC_LOG_ERROR("network", "CHAT: Wrong message type received: %u", type); - recvData.rfinish(); - return; + case CMSG_MESSAGECHAT_SAY: + type = CHAT_MSG_SAY; + break; + case CMSG_MESSAGECHAT_YELL: + type = CHAT_MSG_YELL; + break; + case CMSG_MESSAGECHAT_CHANNEL: + type = CHAT_MSG_CHANNEL; + break; + case CMSG_MESSAGECHAT_WHISPER: + type = CHAT_MSG_WHISPER; + break; + case CMSG_MESSAGECHAT_GUILD: + type = CHAT_MSG_GUILD; + break; + case CMSG_MESSAGECHAT_OFFICER: + type = CHAT_MSG_OFFICER; + break; + case CMSG_MESSAGECHAT_AFK: + type = CHAT_MSG_AFK; + break; + case CMSG_MESSAGECHAT_DND: + type = CHAT_MSG_DND; + break; + case CMSG_MESSAGECHAT_EMOTE: + type = CHAT_MSG_EMOTE; + break; + case CMSG_MESSAGECHAT_PARTY: + type = CHAT_MSG_PARTY; + break; + case CMSG_MESSAGECHAT_RAID: + type = CHAT_MSG_RAID; + break; + case CMSG_MESSAGECHAT_BATTLEGROUND: + type = CHAT_MSG_BATTLEGROUND; + break; + case CMSG_MESSAGECHAT_RAID_WARNING: + type = CHAT_MSG_RAID_WARNING; + break; + default: + TC_LOG_ERROR("network", "HandleMessagechatOpcode : Unknown chat opcode (%u)", recvData.GetOpcode()); + recvData.hexlike(); + return; } - if (lang == LANG_UNIVERSAL && type != CHAT_MSG_AFK && type != CHAT_MSG_DND) + if (type >= MAX_CHAT_MSG_TYPE) { - TC_LOG_ERROR("network", "CMSG_MESSAGECHAT: Possible hacking-attempt: %s tried to send a message in universal language", GetPlayerInfo().c_str()); - SendNotification(LANG_UNKNOWN_LANGUAGE); + TC_LOG_ERROR("network", "CHAT: Wrong message type received: %u", type); recvData.rfinish(); return; } Player* sender = GetPlayer(); - //TC_LOG_DEBUG("CHAT: packet received. type %u, lang %u", type, lang); + //TC_LOG_DEBUG("misc", "CHAT: packet received. type %u, lang %u", type, lang); - // prevent talking at unknown language (cheating) - LanguageDesc const* langDesc = GetLanguageDescByID(lang); - if (!langDesc) + // no language sent with emote packet. + if (type != CHAT_MSG_EMOTE && type != CHAT_MSG_AFK && type != CHAT_MSG_DND) { - SendNotification(LANG_UNKNOWN_LANGUAGE); - recvData.rfinish(); - return; - } + recvData >> lang; - if (langDesc->skill_id != 0 && !sender->HasSkill(langDesc->skill_id)) - { - // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) - Unit::AuraEffectList const& langAuras = sender->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); - bool foundAura = false; - for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) + if (lang == LANG_UNIVERSAL) { - if ((*i)->GetMiscValue() == int32(lang)) - { - foundAura = true; - break; - } + TC_LOG_ERROR("network", "CMSG_MESSAGECHAT: Possible hacking-attempt: %s tried to send a message in universal language", GetPlayerInfo().c_str()); + SendNotification(LANG_UNKNOWN_LANGUAGE); + recvData.rfinish(); + return; } - if (!foundAura) + + // prevent talking at unknown language (cheating) + LanguageDesc const* langDesc = GetLanguageDescByID(lang); + if (!langDesc) { - SendNotification(LANG_NOT_LEARNED_LANGUAGE); + SendNotification(LANG_UNKNOWN_LANGUAGE); recvData.rfinish(); return; } - } - if (lang == LANG_ADDON) - { - // LANG_ADDON is only valid for the following message types - switch (type) + if (langDesc->skill_id != 0 && !sender->HasSkill(langDesc->skill_id)) { - case CHAT_MSG_PARTY: - case CHAT_MSG_RAID: - case CHAT_MSG_GUILD: - case CHAT_MSG_BATTLEGROUND: - case CHAT_MSG_WHISPER: - // check if addon messages are disabled - if (!sWorld->getBoolConfig(CONFIG_ADDON_CHANNEL)) + // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) + Unit::AuraEffectList const& langAuras = sender->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); + bool foundAura = false; + for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) + { + if ((*i)->GetMiscValue() == int32(lang)) { - recvData.rfinish(); - return; + foundAura = true; + break; } - break; - default: - TC_LOG_ERROR("network", "Player %s (GUID: %u) sent a chatmessage with an invalid language/message type combination", - GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow()); - + } + if (!foundAura) + { + SendNotification(LANG_NOT_LEARNED_LANGUAGE); recvData.rfinish(); return; + } } - } - // LANG_ADDON should not be changed nor be affected by flood control - else - { - // send in universal language if player in .gmon mode (ignore spell effects) - if (sender->IsGameMaster()) - lang = LANG_UNIVERSAL; + + if (lang == LANG_ADDON) + { + // LANG_ADDON is only valid for the following message types + switch (type) + { + case CHAT_MSG_PARTY: + case CHAT_MSG_RAID: + case CHAT_MSG_GUILD: + case CHAT_MSG_BATTLEGROUND: + case CHAT_MSG_WHISPER: + // check if addon messages are disabled + if (!sWorld->getBoolConfig(CONFIG_ADDON_CHANNEL)) + { + recvData.rfinish(); + return; + } + break; + default: + TC_LOG_ERROR("network", "Player %s (GUID: %u) sent a chatmessage with an invalid language/message type combination", + GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow()); + + recvData.rfinish(); + return; + } + } + // LANG_ADDON should not be changed nor be affected by flood control else { - Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); - if (!ModLangAuras.empty()) - lang = ModLangAuras.front()->GetMiscValue(); - else if (HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)) + // send in universal language if player in .gm on mode (ignore spell effects) + if (sender->IsGameMaster()) lang = LANG_UNIVERSAL; else { - switch (type) + // send in universal language in two side iteration allowed mode + if (HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)) + lang = LANG_UNIVERSAL; + else { - case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: - case CHAT_MSG_RAID: - case CHAT_MSG_RAID_LEADER: - case CHAT_MSG_RAID_WARNING: - // allow two side chat at group channel if two side group allowed - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) - lang = LANG_UNIVERSAL; - break; - case CHAT_MSG_GUILD: - case CHAT_MSG_OFFICER: - // allow two side chat at guild channel if two side guild allowed - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) - lang = LANG_UNIVERSAL; - break; + switch (type) + { + case CHAT_MSG_PARTY: + case CHAT_MSG_PARTY_LEADER: + case CHAT_MSG_RAID: + case CHAT_MSG_RAID_LEADER: + case CHAT_MSG_RAID_WARNING: + // allow two side chat at group channel if two side group allowed + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) + lang = LANG_UNIVERSAL; + break; + case CHAT_MSG_GUILD: + case CHAT_MSG_OFFICER: + // allow two side chat at guild channel if two side guild allowed + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) + lang = LANG_UNIVERSAL; + break; + } } + + // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used) + Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); + if (!ModLangAuras.empty()) + lang = ModLangAuras.front()->GetMiscValue(); } - } - if (!sender->CanSpeak()) - { - std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); - SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); - recvData.rfinish(); // Prevent warnings - return; + if (!sender->CanSpeak()) + { + std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); + SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); + recvData.rfinish(); // Prevent warnings + return; + } } - - if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND) - sender->UpdateSpeakTime(); } + else + lang = LANG_UNIVERSAL; if (sender->HasAura(1852) && type != CHAT_MSG_WHISPER) { @@ -177,6 +229,8 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; } + uint32 textLength = 0; + uint32 receiverLength = 0; std::string to, channel, msg; bool ignoreChecks = false; switch (type) @@ -185,27 +239,30 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) case CHAT_MSG_EMOTE: case CHAT_MSG_YELL: case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: case CHAT_MSG_GUILD: case CHAT_MSG_OFFICER: case CHAT_MSG_RAID: - case CHAT_MSG_RAID_LEADER: case CHAT_MSG_RAID_WARNING: case CHAT_MSG_BATTLEGROUND: - case CHAT_MSG_BATTLEGROUND_LEADER: - recvData >> msg; + textLength = recvData.ReadBits(9); + msg = recvData.ReadString(textLength); break; case CHAT_MSG_WHISPER: - recvData >> to; - recvData >> msg; + receiverLength = recvData.ReadBits(10); + textLength = recvData.ReadBits(9); + to = recvData.ReadString(receiverLength); + msg = recvData.ReadString(textLength); break; case CHAT_MSG_CHANNEL: - recvData >> channel; - recvData >> msg; + receiverLength = recvData.ReadBits(10); + textLength = recvData.ReadBits(9); + msg = recvData.ReadString(textLength); + channel = recvData.ReadString(receiverLength); break; case CHAT_MSG_AFK: case CHAT_MSG_DND: - recvData >> msg; + textLength = recvData.ReadBits(9); + msg = recvData.ReadString(textLength); ignoreChecks = true; break; } @@ -259,7 +316,8 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) sender->TextEmote(msg); else if (type == CHAT_MSG_YELL) sender->Yell(msg, lang); - } break; + break; + } case CHAT_MSG_WHISPER: { if (!normalizePlayerName(to)) @@ -299,7 +357,8 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) sender->AddWhisperWhiteList(receiver->GetGUID()); GetPlayer()->Whisper(msg, lang, receiver->GetGUID()); - } break; + break; + } case CHAT_MSG_PARTY: case CHAT_MSG_PARTY_LEADER: { @@ -312,15 +371,16 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; } - if (type == CHAT_MSG_PARTY_LEADER && !group->IsLeader(sender->GetGUID())) - return; + if (group->IsLeader(GetPlayer()->GetGUID())) + type = CHAT_MSG_PARTY_LEADER; sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPacket data; ChatHandler::BuildChatPacket(data, ChatMsg(type), Language(lang), sender, NULL, msg); group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID())); - } break; + break; + } case CHAT_MSG_GUILD: { if (GetPlayer()->GetGuildId()) @@ -332,7 +392,8 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) guild->BroadcastToGuild(this, false, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } } - } break; + break; + } case CHAT_MSG_OFFICER: { if (GetPlayer()->GetGuildId()) @@ -344,8 +405,10 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) guild->BroadcastToGuild(this, true, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } } - } break; + break; + } case CHAT_MSG_RAID: + case CHAT_MSG_RAID_LEADER: { // if player is in battleground, he cannot say to battleground members by /ra Group* group = GetPlayer()->GetOriginalGroup(); @@ -356,29 +419,16 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; } - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID, Language(lang), sender, NULL, msg); - group->BroadcastPacket(&data, false); - } break; - case CHAT_MSG_RAID_LEADER: - { - // if player is in battleground, he cannot say to battleground members by /ra - Group* group = GetPlayer()->GetOriginalGroup(); - if (!group) - { - group = GetPlayer()->GetGroup(); - if (!group || group->isBGGroup() || !group->isRaidGroup() || !group->IsLeader(sender->GetGUID())) - return; - } + if (group->IsLeader(GetPlayer()->GetGUID())) + type = CHAT_MSG_RAID_LEADER; sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_LEADER, Language(lang), sender, NULL, msg); + ChatHandler::BuildChatPacket(data, ChatMsg(type), Language(lang), sender, NULL, msg); group->BroadcastPacket(&data, false); - } break; + break; + } case CHAT_MSG_RAID_WARNING: { Group* group = GetPlayer()->GetGroup(); @@ -391,33 +441,26 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) //in battleground, raid warning is sent only to players in battleground - code is ok ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_WARNING, Language(lang), sender, NULL, msg); group->BroadcastPacket(&data, false); - } break; + break; + } case CHAT_MSG_BATTLEGROUND: - { - //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() - Group* group = GetPlayer()->GetGroup(); - if (!group || !group->isBGGroup()) - return; - - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_BATTLEGROUND, Language(lang), sender, NULL, msg); - group->BroadcastPacket(&data, false); - } break; case CHAT_MSG_BATTLEGROUND_LEADER: { // battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() Group* group = GetPlayer()->GetGroup(); - if (!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID())) + if (!group || !group->isBGGroup()) return; + if (group->IsLeader(GetPlayer()->GetGUID())) + type = CHAT_MSG_BATTLEGROUND_LEADER; + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_BATTLEGROUND_LEADER, Language(lang), sender, NULL, msg);; + ChatHandler::BuildChatPacket(data, ChatMsg(type), Language(lang), sender, NULL, msg); group->BroadcastPacket(&data, false); - } break; + break; + } case CHAT_MSG_CHANNEL: { if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHAT_CHANNEL_REQ)) @@ -437,17 +480,18 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) chn->Say(sender->GetGUID(), msg.c_str(), lang); } } - } break; + break; + } case CHAT_MSG_AFK: { if (!sender->IsInCombat()) { - if (sender->isAFK()) // Already AFK + if (sender ->isAFK()) // Already AFK { if (msg.empty()) - sender->ToggleAFK(); // Remove AFK + sender->ToggleAFK(); // Remove AFK else - sender->autoReplyMsg = msg; // Update message + sender->autoReplyMsg = msg; // Update message } else // New AFK mode { @@ -465,12 +509,12 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } case CHAT_MSG_DND: { - if (sender->isDND()) // Already DND + if (sender->isDND()) // Already DND { if (msg.empty()) - sender->ToggleDND(); // Remove DND + sender->ToggleDND(); // Remove DND else - sender->autoReplyMsg = msg; // Update message + sender->autoReplyMsg = msg; // Update message } else // New DND mode { @@ -491,6 +535,140 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } } +void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData) +{ + Player* sender = GetPlayer(); + ChatMsg type; + + switch (recvData.GetOpcode()) + { + case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND: + type = CHAT_MSG_BATTLEGROUND; + break; + case CMSG_MESSAGECHAT_ADDON_GUILD: + type = CHAT_MSG_GUILD; + break; + case CMSG_MESSAGECHAT_ADDON_OFFICER: + type = CHAT_MSG_OFFICER; + break; + case CMSG_MESSAGECHAT_ADDON_PARTY: + type = CHAT_MSG_PARTY; + break; + case CMSG_MESSAGECHAT_ADDON_RAID: + type = CHAT_MSG_RAID; + break; + case CMSG_MESSAGECHAT_ADDON_WHISPER: + type = CHAT_MSG_WHISPER; + break; + default: + TC_LOG_ERROR("network", "HandleAddonMessagechatOpcode: Unknown addon chat opcode (%u)", recvData.GetOpcode()); + recvData.hexlike(); + return; + } + + std::string message; + std::string prefix; + std::string targetName; + + switch (type) + { + case CHAT_MSG_WHISPER: + { + uint32 msgLen = recvData.ReadBits(9); + uint32 prefixLen = recvData.ReadBits(5); + uint32 targetLen = recvData.ReadBits(10); + message = recvData.ReadString(msgLen); + prefix = recvData.ReadString(prefixLen); + targetName = recvData.ReadString(targetLen); + break; + } + case CHAT_MSG_PARTY: + case CHAT_MSG_RAID: + case CHAT_MSG_OFFICER: + { + uint32 prefixLen = recvData.ReadBits(5); + uint32 msgLen = recvData.ReadBits(9); + prefix = recvData.ReadString(prefixLen); + message = recvData.ReadString(msgLen); + break; + } + case CHAT_MSG_GUILD: + case CHAT_MSG_BATTLEGROUND: + { + uint32 msgLen = recvData.ReadBits(9); + uint32 prefixLen = recvData.ReadBits(5); + message = recvData.ReadString(msgLen); + prefix = recvData.ReadString(prefixLen); + break; + } + default: + break; + } + + if (prefix.empty() || prefix.length() > 16) + return; + + // Disabled addon channel? + if (!sWorld->getBoolConfig(CONFIG_ADDON_CHANNEL)) + { + recvData.rfinish(); + return; + } + + switch (type) + { + case CHAT_MSG_BATTLEGROUND: + { + Group* group = sender->GetGroup(); + if (!group || !group->isBGGroup()) + return; + + WorldPacket data; + ChatHandler::BuildChatPacket(data, type, LANG_ADDON, sender, NULL, message, 0U, "", DEFAULT_LOCALE, prefix); + group->BroadcastAddonMessagePacket(&data, prefix, false); + break; + } + case CHAT_MSG_GUILD: + case CHAT_MSG_OFFICER: + { + if (sender->GetGuildId()) + if (Guild* guild = sGuildMgr->GetGuildById(sender->GetGuildId())) + guild->BroadcastAddonToGuild(this, type == CHAT_MSG_OFFICER, message, prefix); + break; + } + case CHAT_MSG_WHISPER: + { + if (!normalizePlayerName(targetName)) + break; + Player* receiver = sObjectAccessor->FindPlayerByName(targetName); + if (!receiver) + break; + + sender->WhisperAddon(message, prefix, receiver); + break; + } + // Messages sent to "RAID" while in a party will get delivered to "PARTY" + case CHAT_MSG_PARTY: + case CHAT_MSG_RAID: + { + + Group* group = sender->GetGroup(); + if (!group || group->isBGGroup()) + break; + + WorldPacket data; + ChatHandler::BuildChatPacket(data, type, LANG_ADDON, sender, NULL, message, 0U, "", DEFAULT_LOCALE, prefix); + group->BroadcastAddonMessagePacket(&data, prefix, true, -1, group->GetMemberGroup(sender->GetGUID())); + break; + } + default: + { + TC_LOG_ERROR("misc", "HandleAddonMessagechatOpcode: unknown addon message type %u", type); + break; + } + } +} + void WorldSession::HandleEmoteOpcode(WorldPacket& recvData) { if (!GetPlayer()->IsAlive() || GetPlayer()->HasUnitState(UNIT_STATE_DIED)) @@ -589,7 +767,7 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData) TypeContainerVisitor<Trinity::PlayerDistWorker<Trinity::LocalizedPacketDo<Trinity::EmoteChatBuilder> >, WorldTypeMapContainer> message(emote_worker); cell.Visit(p, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); + GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, 0, unit); //Send scripted event call if (unit && unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->AI()) @@ -598,14 +776,30 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData) void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recvData) { - uint64 iguid; + ObjectGuid guid; uint8 unk; //TC_LOG_DEBUG("network", "WORLD: Received CMSG_CHAT_IGNORED"); - recvData >> iguid; recvData >> unk; // probably related to spam reporting - - Player* player = ObjectAccessor::FindPlayer(iguid); + guid[5] = recvData.ReadBit(); + guid[2] = recvData.ReadBit(); + guid[6] = recvData.ReadBit(); + guid[4] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + guid[0] = recvData.ReadBit(); + guid[1] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[6]); + recvData.ReadByteSeq(guid[5]); + recvData.ReadByteSeq(guid[1]); + recvData.ReadByteSeq(guid[4]); + recvData.ReadByteSeq(guid[3]); + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[2]); + + Player* player = ObjectAccessor::FindPlayer(guid); if (!player || !player->GetSession()) return; diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index 5b35da297c9..d74aebaaa1f 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -32,6 +32,7 @@ #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "SpellAuraEffects.h" class Aura; @@ -48,11 +49,12 @@ class Aura; void WorldSession::SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res, uint32 val /* = 0 */) { - WorldPacket data(SMSG_PARTY_COMMAND_RESULT, 4 + member.size() + 1 + 4 + 4); + WorldPacket data(SMSG_PARTY_COMMAND_RESULT, 4 + member.size() + 1 + 4 + 4 + 8); data << uint32(operation); data << member; data << uint32(res); data << uint32(val); // LFD cooldown related (used with ERR_PARTY_LFG_BOOT_COOLDOWN_S and ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S) + data << uint64(0); // player who caused error (in some cases). SendPacket(&data); } @@ -61,59 +63,91 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_INVITE"); - std::string membername; - recvData >> membername; - recvData.read_skip<uint32>(); + ObjectGuid crossRealmGuid; // unused + + recvData.read_skip<uint32>(); // Non-zero in cross realm invites + recvData.read_skip<uint32>(); // Always 0 + + crossRealmGuid[2] = recvData.ReadBit(); + crossRealmGuid[7] = recvData.ReadBit(); + + uint8 realmLen = recvData.ReadBits(9); + + crossRealmGuid[3] = recvData.ReadBit(); + + uint8 nameLen = recvData.ReadBits(10); + + crossRealmGuid[5] = recvData.ReadBit(); + crossRealmGuid[4] = recvData.ReadBit(); + crossRealmGuid[6] = recvData.ReadBit(); + crossRealmGuid[0] = recvData.ReadBit(); + crossRealmGuid[1] = recvData.ReadBit(); + + recvData.ReadByteSeq(crossRealmGuid[4]); + recvData.ReadByteSeq(crossRealmGuid[7]); + recvData.ReadByteSeq(crossRealmGuid[6]); + + std::string memberName, realmName; + memberName = recvData.ReadString(nameLen); + realmName = recvData.ReadString(realmLen); // unused + + recvData.ReadByteSeq(crossRealmGuid[1]); + recvData.ReadByteSeq(crossRealmGuid[0]); + recvData.ReadByteSeq(crossRealmGuid[5]); + recvData.ReadByteSeq(crossRealmGuid[3]); + recvData.ReadByteSeq(crossRealmGuid[2]); // attempt add selected player // cheating - if (!normalizePlayerName(membername)) + if (!normalizePlayerName(memberName)) { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_BAD_PLAYER_NAME_S); return; } - Player* player = sObjectAccessor->FindPlayerByName(membername); + Player* player = sObjectAccessor->FindPlayerByName(memberName); // no player if (!player) { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_BAD_PLAYER_NAME_S); return; } // restrict invite to GMs if (!sWorld->getBoolConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->IsGameMaster() && player->IsGameMaster()) { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_BAD_PLAYER_NAME_S); return; } // can't group with if (!GetPlayer()->IsGameMaster() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam()) { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_PLAYER_WRONG_FACTION); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_PLAYER_WRONG_FACTION); return; } if (GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId()) { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_TARGET_NOT_IN_INSTANCE_S); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_TARGET_NOT_IN_INSTANCE_S); return; } // just ignore us if (player->GetInstanceId() != 0 && player->GetDungeonDifficulty() != GetPlayer()->GetDungeonDifficulty()) { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_IGNORING_YOU_S); return; } if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_IGNORING_YOU_S); return; } + ObjectGuid invitedGuid = player->GetGUID(); + Group* group = GetPlayer()->GetGroup(); if (group && group->isBGGroup()) group = GetPlayer()->GetOriginalGroup(); @@ -124,17 +158,63 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) // player already in another group or invited if (group2 || player->GetGroupInvite()) { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_ALREADY_IN_GROUP_S); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_ALREADY_IN_GROUP_S); if (group2) { // tell the player that they were invited but it failed as they were already in a group - WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size - data << uint8(0); // invited/already in group flag - data << GetPlayer()->GetName(); // max len 48 - data << uint32(0); // unk - data << uint8(0); // count - data << uint32(0); // unk + WorldPacket data(SMSG_GROUP_INVITE, 45); + + data.WriteBit(0); + + data.WriteBit(invitedGuid[0]); + data.WriteBit(invitedGuid[3]); + data.WriteBit(invitedGuid[2]); + + data.WriteBit(0); // Inverse already in group + + data.WriteBit(invitedGuid[6]); + data.WriteBit(invitedGuid[5]); + + data.WriteBits(0, 9); // Realm name + + data.WriteBit(invitedGuid[4]); + + data.WriteBits(GetPlayer()->GetName().size(), 7); // Inviter name length + + data.WriteBits(0, 24); // Count 2 + + data.WriteBit(0); + + data.WriteBit(invitedGuid[1]); + data.WriteBit(invitedGuid[7]); + + data.FlushBits(); + + data.WriteByteSeq(invitedGuid[1]); + data.WriteByteSeq(invitedGuid[4]); + + data << int32(getMSTime()); + data << int32(0); + data << int32(0); + + data.WriteByteSeq(invitedGuid[6]); + data.WriteByteSeq(invitedGuid[0]); + data.WriteByteSeq(invitedGuid[2]); + data.WriteByteSeq(invitedGuid[3]); + + // for count2 { int32(0) } + + data.WriteByteSeq(invitedGuid[5]); + + // data.append(realm name); + + data.WriteByteSeq(invitedGuid[7]); + + data.WriteString(GetPlayer()->GetName()); // inviter name + + data << int32(0); + player->GetSession()->SendPacket(&data); } @@ -185,90 +265,138 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) } // ok, we do it - WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size - data << uint8(1); // invited/already in group flag - data << GetPlayer()->GetName(); // max len 48 - data << uint32(0); // unk - data << uint8(0); // count - data << uint32(0); // unk + WorldPacket data(SMSG_GROUP_INVITE, 45); + + data.WriteBit(0); + + data.WriteBit(invitedGuid[0]); + data.WriteBit(invitedGuid[3]); + data.WriteBit(invitedGuid[2]); + + data.WriteBit(1); // Inverse already in group + + data.WriteBit(invitedGuid[6]); + data.WriteBit(invitedGuid[5]); + + data.WriteBits(0, 9); // Realm name + + data.WriteBit(invitedGuid[4]); + + data.WriteBits(GetPlayer()->GetName().size(), 7); // Inviter name length + + data.WriteBits(0, 24); // Count 2 + + data.WriteBit(0); + + data.WriteBit(invitedGuid[1]); + data.WriteBit(invitedGuid[7]); + + data.FlushBits(); + + data.WriteByteSeq(invitedGuid[1]); + data.WriteByteSeq(invitedGuid[4]); + + data << int32(getMSTime()); + data << int32(0); + data << int32(0); + + data.WriteByteSeq(invitedGuid[6]); + data.WriteByteSeq(invitedGuid[0]); + data.WriteByteSeq(invitedGuid[2]); + data.WriteByteSeq(invitedGuid[3]); + + // for count2 { int32(0) } + + data.WriteByteSeq(invitedGuid[5]); + + // data.append(realm name); + + data.WriteByteSeq(invitedGuid[7]); + + data.WriteString(GetPlayer()->GetName()); + + data << int32(0); + player->GetSession()->SendPacket(&data); - SendPartyResult(PARTY_OP_INVITE, membername, ERR_PARTY_RESULT_OK); + SendPartyResult(PARTY_OP_INVITE, memberName, ERR_PARTY_RESULT_OK); } -void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recvData) +void WorldSession::HandleGroupInviteResponseOpcode(WorldPacket& recvData) { - TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_ACCEPT"); + TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_INVITE_RESPONSE"); - recvData.read_skip<uint32>(); - Group* group = GetPlayer()->GetGroupInvite(); + recvData.ReadBit(); // unk always 0 + bool accept = recvData.ReadBit(); - if (!group) - return; + // Never actually received? + /*if (accept) + recvData.read_skip<uint32>(); // unk*/ - // Remove player from invitees in any case - group->RemoveInvite(GetPlayer()); + Group* group = GetPlayer()->GetGroupInvite(); - if (group->GetLeaderGUID() == GetPlayer()->GetGUID()) - { - TC_LOG_ERROR("network", "HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow()); + if (!group) return; - } - // Group is full - if (group->IsFull()) + if (accept) { - SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); - return; - } + // Remove player from invitees in any case + group->RemoveInvite(GetPlayer()); - Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()); - - // Forming a new group, create it - if (!group->IsCreated()) - { - // This can happen if the leader is zoning. To be removed once delayed actions for zoning are implemented - if (!leader) + if (group->GetLeaderGUID() == GetPlayer()->GetGUID()) { - group->RemoveAllInvites(); + TC_LOG_ERROR("network", "HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow()); return; } - // If we're about to create a group there really should be a leader present - ASSERT(leader); - group->RemoveInvite(leader); - group->Create(leader); - sGroupMgr->AddGroup(group); - } + // Group is full + if (group->IsFull()) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); + return; + } - // Everything is fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! - if (!group->AddMember(GetPlayer())) - return; + Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()); - group->BroadcastGroupUpdate(); -} + // Forming a new group, create it + if (!group->IsCreated()) + { + // This can happen if the leader is zoning. To be removed once delayed actions for zoning are implemented + if (!leader) + { + group->RemoveAllInvites(); + return; + } -void WorldSession::HandleGroupDeclineOpcode(WorldPacket & /*recvData*/) -{ - TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_DECLINE"); + // If we're about to create a group there really should be a leader present + ASSERT(leader); + group->RemoveInvite(leader); + group->Create(leader); + sGroupMgr->AddGroup(group); + } - Group* group = GetPlayer()->GetGroupInvite(); - if (!group) - return; + // Everything is fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! + if (!group->AddMember(GetPlayer())) + return; - // Remember leader if online (group pointer will be invalid if group gets disbanded) - Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()); + group->BroadcastGroupUpdate(); + } + else + { + // Remember leader if online (group pointer will be invalid if group gets disbanded) + Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()); - // uninvite, group can be deleted - GetPlayer()->UninviteFromGroup(); + // uninvite, group can be deleted + GetPlayer()->UninviteFromGroup(); - if (!leader || !leader->GetSession()) - return; + if (!leader || !leader->GetSession()) + return; - // report - WorldPacket data(SMSG_GROUP_DECLINE, GetPlayer()->GetName().length()); - data << GetPlayer()->GetName(); - leader->GetSession()->SendPacket(&data); + // report + WorldPacket data(SMSG_GROUP_DECLINE, GetPlayer()->GetName().size()); + data << GetPlayer()->GetName(); + leader->GetSession()->SendPacket(&data); + } } void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket& recvData) @@ -386,7 +514,81 @@ void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket& recvData) group->SendUpdate(); } -void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleGroupSetRolesOpcode(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_SET_ROLES"); + + uint32 newRole; + ObjectGuid guid1; // Assigner GUID + ObjectGuid guid2; // Target GUID + + guid1 = GetPlayer()->GetGUID(); + + recvData >> newRole; + + guid2[2] = recvData.ReadBit(); + guid2[6] = recvData.ReadBit(); + guid2[3] = recvData.ReadBit(); + guid2[7] = recvData.ReadBit(); + guid2[5] = recvData.ReadBit(); + guid2[1] = recvData.ReadBit(); + guid2[0] = recvData.ReadBit(); + guid2[4] = recvData.ReadBit(); + + recvData.ReadByteSeq(guid2[6]); + recvData.ReadByteSeq(guid2[4]); + recvData.ReadByteSeq(guid2[1]); + recvData.ReadByteSeq(guid2[3]); + recvData.ReadByteSeq(guid2[0]); + recvData.ReadByteSeq(guid2[5]); + recvData.ReadByteSeq(guid2[2]); + recvData.ReadByteSeq(guid2[7]); + + WorldPacket data(SMSG_GROUP_SET_ROLE, 24); + + data.WriteBit(guid1[1]); + data.WriteBit(guid2[0]); + data.WriteBit(guid2[2]); + data.WriteBit(guid2[4]); + data.WriteBit(guid2[7]); + data.WriteBit(guid2[3]); + data.WriteBit(guid1[7]); + data.WriteBit(guid2[5]); + data.WriteBit(guid1[5]); + data.WriteBit(guid1[4]); + data.WriteBit(guid1[3]); + data.WriteBit(guid2[6]); + data.WriteBit(guid1[2]); + data.WriteBit(guid1[6]); + data.WriteBit(guid2[1]); + data.WriteBit(guid1[0]); + + data.WriteByteSeq(guid1[7]); + data.WriteByteSeq(guid2[3]); + data.WriteByteSeq(guid1[6]); + data.WriteByteSeq(guid2[4]); + data.WriteByteSeq(guid2[0]); + data << uint32(newRole); // New Role + data.WriteByteSeq(guid2[6]); + data.WriteByteSeq(guid2[2]); + data.WriteByteSeq(guid1[0]); + data.WriteByteSeq(guid1[4]); + data.WriteByteSeq(guid2[1]); + data.WriteByteSeq(guid1[3]); + data.WriteByteSeq(guid1[5]); + data.WriteByteSeq(guid1[2]); + data.WriteByteSeq(guid2[5]); + data.WriteByteSeq(guid2[7]); + data.WriteByteSeq(guid1[1]); + data << uint32(0); // Old Role + + if (GetPlayer()->GetGroup()) + GetPlayer()->GetGroup()->BroadcastPacket(&data, false); + else + SendPacket(&data); +} + +void WorldSession::HandleGroupDisbandOpcode(WorldPacket& /*recvData*/) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_DISBAND"); @@ -480,7 +682,7 @@ void WorldSession::HandleMinimapPingOpcode(WorldPacket& recvData) recvData >> x; recvData >> y; - //TC_LOG_DEBUG("Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y); + //TC_LOG_DEBUG("misc", "Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y); /** error handling **/ /********************/ @@ -509,7 +711,7 @@ void WorldSession::HandleRandomRollOpcode(WorldPacket& recvData) // everything's fine, do it roll = urand(minimum, maximum); - //TC_LOG_DEBUG("ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll); + //TC_LOG_DEBUG("misc", "ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll); WorldPacket data(MSG_RANDOM_ROLL, 4+4+4+8); data << uint32(minimum); @@ -530,7 +732,7 @@ void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket& recvData) if (!group) return; - uint8 x; + uint8 x; recvData >> x; /** error handling **/ @@ -538,9 +740,7 @@ void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket& recvData) // everything's fine, do it if (x == 0xFF) // target icon request - { group->SendTargetIconList(this); - } else // target icon update { if (group->isRaidGroup() && !group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) @@ -561,7 +761,7 @@ void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket& recvData) } } -void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_RAID_CONVERT"); @@ -572,14 +772,22 @@ void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recvData*/) if (_player->InBattleground()) return; - /** error handling **/ + // error handling if (!group->IsLeader(GetPlayer()->GetGUID()) || group->GetMembersCount() < 2) return; - /********************/ // everything's fine, do it (is it 0 (PARTY_OP_INVITE) correct code) SendPartyResult(PARTY_OP_INVITE, "", ERR_PARTY_RESULT_OK); - group->ConvertToRaid(); + + // New 4.x: it is now possible to convert a raid to a group if member count is 5 or less + + bool toRaid; + recvData >> toRaid; + + if (toRaid) + group->ConvertToRaid(); + else + group->ConvertToGroup(); } void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket& recvData) @@ -608,10 +816,9 @@ void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket& recvData) Player* movedPlayer = sObjectAccessor->FindPlayerByName(name); uint64 guid; + if (movedPlayer) - { guid = movedPlayer->GetGUID(); - } else { CharacterDatabase.EscapeString(name); @@ -621,6 +828,16 @@ void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket& recvData) group->ChangeMembersGroup(guid, groupNr); } +void WorldSession::HandleGroupSwapSubGroupOpcode(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_SWAP_SUB_GROUP"); + std::string unk1; + std::string unk2; + + recvData >> unk1; + recvData >> unk2; +} + void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_GROUP_ASSISTANT_LEADER"); @@ -709,7 +926,7 @@ void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket& recvData) } } -void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket& /*recvData*/) { //Group* group = GetPlayer()->GetGroup(); //if (!group) @@ -728,18 +945,15 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke if (mask == GROUP_UPDATE_FLAG_NONE) return; + std::set<uint32> const& phases = player->GetPhases(); + if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); - uint32 byteCount = 0; - for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i) - if (mask & (1 << i)) - byteCount += GroupUpdateLength[i]; - - data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount); + data->Initialize(SMSG_PARTY_MEMBER_STATS, 80); // average value data->append(player->GetPackGUID()); *data << uint32(mask); @@ -791,23 +1005,47 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke if (mask & GROUP_UPDATE_FLAG_ZONE) *data << uint16(player->GetZoneId()); + if (mask & GROUP_UPDATE_FLAG_UNK100) + *data << uint16(0); + if (mask & GROUP_UPDATE_FLAG_POSITION) { *data << uint16(player->GetPositionX()); *data << uint16(player->GetPositionY()); + *data << uint16(player->GetPositionZ()); } if (mask & GROUP_UPDATE_FLAG_AURAS) { + *data << uint8(0); uint64 auramask = player->GetAuraUpdateMaskForRaid(); *data << uint64(auramask); + *data << uint32(MAX_AURAS); // count for (uint32 i = 0; i < MAX_AURAS; ++i) { if (auramask & (uint64(1) << i)) { AuraApplication const* aurApp = player->GetVisibleAura(i); - *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); - *data << uint8(1); + if (!aurApp) + { + *data << uint32(0); + *data << uint16(0); + continue; + } + + *data << uint32(aurApp->GetBase()->GetId()); + *data << uint16(aurApp->GetFlags()); + + if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) + *data << int32(eff->GetAmount()); + else + *data << int32(0); + } + } } } } @@ -816,9 +1054,9 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke if (mask & GROUP_UPDATE_FLAG_PET_GUID) { if (pet) - *data << (uint64) pet->GetGUID(); + *data << uint64(pet->GetGUID()); else - *data << (uint64) 0; + *data << uint64(0); } if (mask & GROUP_UPDATE_FLAG_PET_NAME) @@ -881,20 +1119,43 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke { if (pet) { + *data << uint8(0); uint64 auramask = pet->GetAuraUpdateMaskForRaid(); *data << uint64(auramask); + *data << uint32(MAX_AURAS); // count for (uint32 i = 0; i < MAX_AURAS; ++i) { if (auramask & (uint64(1) << i)) { AuraApplication const* aurApp = pet->GetVisibleAura(i); - *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); - *data << uint8(aurApp ? aurApp->GetFlags() : 0); + if (!aurApp) + { + *data << uint32(0); + *data << uint16(0); + continue; + } + + *data << uint32(aurApp->GetBase()->GetId()); + *data << uint16(aurApp->GetFlags()); + + if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) + *data << int32(eff->GetAmount()); + else + *data << int32(0); + } + } } } } else + { + *data << uint8(0); *data << uint64(0); + } } if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) @@ -903,22 +1164,31 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke *data << uint32(veh->GetVehicleInfo()->m_seatID[player->m_movementInfo.transport.seat]); else *data << uint32(0); + + } + + if (mask & GROUP_UPDATE_FLAG_PHASE) + { + *data << uint32(phases.empty() ? 8 : 0); + *data << uint32(phases.size()); + for (std::set<uint32>::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) + *data << uint16(*itr); } } /*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ -void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recvData) +void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS"); - uint64 Guid; - recvData >> Guid; + uint64 guid; + recvData >> guid; - Player* player = HashMapHolder<Player>::Find(Guid); + Player* player = HashMapHolder<Player>::Find(guid); if (!player) { WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data.appendPackGUID(Guid); + data.appendPackGUID(guid); data << uint32(GROUP_UPDATE_FLAG_STATUS); data << uint16(MEMBER_STATUS_OFFLINE); SendPacket(&data); @@ -927,6 +1197,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recvData) Pet* pet = player->GetPet(); Powers powerType = player->getPowerType(); + std::set<uint32> const& phases = player->GetPhases(); WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related @@ -947,6 +1218,9 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recvData) if (player->GetVehicle()) updateFlags |= GROUP_UPDATE_FLAG_VEHICLE_SEAT; + if (!phases.empty()) + updateFlags |= GROUP_UPDATE_FLAG_PHASE; + uint16 playerStatus = MEMBER_STATUS_ONLINE; if (player->IsPvP()) playerStatus |= MEMBER_STATUS_PVP; @@ -981,21 +1255,38 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recvData) data << uint16(player->GetZoneId()); // GROUP_UPDATE_FLAG_ZONE data << uint16(player->GetPositionX()); // GROUP_UPDATE_FLAG_POSITION data << uint16(player->GetPositionY()); // GROUP_UPDATE_FLAG_POSITION + data << uint16(player->GetPositionZ()); // GROUP_UPDATE_FLAG_POSITION - uint64 auraMask = 0; + // GROUP_UPDATE_FLAG_AURAS + data << uint8(1); + uint64 auramask = 0; size_t maskPos = data.wpos(); - data << uint64(auraMask); // placeholder + data << uint64(auramask); // placeholder + data << uint32(MAX_AURAS); // count + for (uint8 i = 0; i < MAX_AURAS; ++i) { if (AuraApplication const* aurApp = player->GetVisibleAura(i)) { - auraMask |= uint64(1) << i; + auramask |= (uint64(1) << i); + data << uint32(aurApp->GetBase()->GetId()); - data << uint8(aurApp->GetFlags()); + data << uint16(aurApp->GetFlags()); + + if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) + data << int32(eff->GetAmount()); + else + data << int32(0); + } + } } } - data.put<uint64>(maskPos, auraMask); // GROUP_UPDATE_FLAG_AURAS + data.put<uint64>(maskPos, auramask); // GROUP_UPDATE_FLAG_AURAS if (updateFlags & GROUP_UPDATE_FLAG_PET_GUID) data << uint64(pet->GetGUID()); @@ -1018,18 +1309,33 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recvData) if (updateFlags & GROUP_UPDATE_FLAG_PET_MAX_POWER) data << uint16(pet->GetMaxPower(pet->getPowerType())); + // GROUP_UPDATE_FLAG_PET_AURAS uint64 petAuraMask = 0; + data << uint8(1); maskPos = data.wpos(); data << uint64(petAuraMask); // placeholder + data << uint32(MAX_AURAS); // count if (pet) { for (uint8 i = 0; i < MAX_AURAS; ++i) { if (AuraApplication const* aurApp = pet->GetVisibleAura(i)) { - petAuraMask |= uint64(1) << i; + petAuraMask |= (uint64(1) << i); + data << uint32(aurApp->GetBase()->GetId()); - data << uint8(aurApp->GetFlags()); + data << uint16(aurApp->GetFlags()); + + if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) + data << int32(eff->GetAmount()); + else + data << int32(0); + } + } } } } @@ -1039,31 +1345,34 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recvData) if (updateFlags & GROUP_UPDATE_FLAG_VEHICLE_SEAT) data << uint32(player->GetVehicle()->GetVehicleInfo()->m_seatID[player->m_movementInfo.transport.seat]); + if (updateFlags & GROUP_UPDATE_FLAG_PHASE) + { + data << uint32(phases.empty() ? 8 : 0); + data << uint32(phases.size()); + for (std::set<uint32>::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) + data << uint16(*itr); + } + SendPacket(&data); } -/*!*/void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket& /*recvData*/) { // every time the player checks the character screen _player->SendRaidInfo(); } -/*void WorldSession::HandleGroupCancelOpcode(WorldPacket& recvData) -{ - TC_LOG_DEBUG("WORLD: got CMSG_GROUP_CANCEL."); -}*/ - void WorldSession::HandleOptOutOfLootOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_OPT_OUT_OF_LOOT"); - uint32 passOnLoot; + bool passOnLoot; recvData >> passOnLoot; // 1 always pass, 0 do not pass // ignore if player not loaded if (!GetPlayer()) // needed because STATUS_AUTHED { - if (passOnLoot != 0) + if (passOnLoot) TC_LOG_ERROR("network", "CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!"); return; } diff --git a/src/server/game/Handlers/GuildFinderHandler.cpp b/src/server/game/Handlers/GuildFinderHandler.cpp new file mode 100644 index 00000000000..14175b44d9f --- /dev/null +++ b/src/server/game/Handlers/GuildFinderHandler.cpp @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "WorldSession.h" +#include "WorldPacket.h" +#include "Object.h" +#include "SharedDefines.h" +#include "GuildFinderMgr.h" +#include "GuildMgr.h" + +void WorldSession::HandleGuildFinderAddRecruit(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_ADD_RECRUIT"); + + if (sGuildFinderMgr->GetAllMembershipRequestsForPlayer(GetPlayer()->GetGUIDLow()).size() == 10) + return; + + uint32 classRoles = 0; + uint32 availability = 0; + uint32 guildInterests = 0; + + recvPacket >> classRoles >> guildInterests >> availability; + + ObjectGuid guid; + guid[3] = recvPacket.ReadBit(); + guid[0] = recvPacket.ReadBit(); + guid[6] = recvPacket.ReadBit(); + guid[1] = recvPacket.ReadBit(); + uint16 commentLength = recvPacket.ReadBits(11); + guid[5] = recvPacket.ReadBit(); + guid[4] = recvPacket.ReadBit(); + guid[7] = recvPacket.ReadBit(); + uint8 nameLength = recvPacket.ReadBits(7); + guid[2] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guid[4]); + recvPacket.ReadByteSeq(guid[5]); + std::string comment = recvPacket.ReadString(commentLength); + std::string playerName = recvPacket.ReadString(nameLength); + recvPacket.ReadByteSeq(guid[7]); + recvPacket.ReadByteSeq(guid[2]); + recvPacket.ReadByteSeq(guid[0]); + recvPacket.ReadByteSeq(guid[6]); + recvPacket.ReadByteSeq(guid[1]); + recvPacket.ReadByteSeq(guid[3]); + + uint32 guildLowGuid = GUID_LOPART(uint64(guid)); + + if (!IS_GUILD_GUID(guid)) + return; + if (!(classRoles & GUILDFINDER_ALL_ROLES) || classRoles > GUILDFINDER_ALL_ROLES) + return; + if (!(availability & AVAILABILITY_ALWAYS) || availability > AVAILABILITY_ALWAYS) + return; + if (!(guildInterests & ALL_INTERESTS) || guildInterests > ALL_INTERESTS) + return; + + MembershipRequest request = MembershipRequest(GetPlayer()->GetGUIDLow(), guildLowGuid, availability, classRoles, guildInterests, comment, time(NULL)); + sGuildFinderMgr->AddMembershipRequest(guildLowGuid, request); +} + +void WorldSession::HandleGuildFinderBrowse(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_BROWSE"); + uint32 classRoles = 0; + uint32 availability = 0; + uint32 guildInterests = 0; + uint32 playerLevel = 0; // Raw player level (1-85), do they use MAX_FINDER_LEVEL when on level 85 ? + + recvPacket >> classRoles >> availability >> guildInterests >> playerLevel; + + if (!(classRoles & GUILDFINDER_ALL_ROLES) || classRoles > GUILDFINDER_ALL_ROLES) + return; + if (!(availability & AVAILABILITY_ALWAYS) || availability > AVAILABILITY_ALWAYS) + return; + if (!(guildInterests & ALL_INTERESTS) || guildInterests > ALL_INTERESTS) + return; + if (playerLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || playerLevel < 1) + return; + + Player* player = GetPlayer(); + + LFGuildPlayer settings(player->GetGUIDLow(), classRoles, availability, guildInterests, ANY_FINDER_LEVEL); + LFGuildStore guildList = sGuildFinderMgr->GetGuildsMatchingSetting(settings, player->GetTeamId()); + uint32 guildCount = guildList.size(); + + if (guildCount == 0) + { + WorldPacket packet(SMSG_LF_GUILD_BROWSE_UPDATED, 0); + player->SendDirectMessage(&packet); + return; + } + + ByteBuffer bufferData(65 * guildCount); + WorldPacket data(SMSG_LF_GUILD_BROWSE_UPDATED, 3 + guildCount * 65); // Estimated size + data.WriteBits(guildCount, 19); + + for (LFGuildStore::const_iterator itr = guildList.begin(); itr != guildList.end(); ++itr) + { + LFGuildSettings guildSettings = itr->second; + Guild* guild = sGuildMgr->GetGuildById(itr->first); + + ObjectGuid guildGUID = ObjectGuid(guild->GetGUID()); + + data.WriteBit(guildGUID[7]); + data.WriteBit(guildGUID[5]); + data.WriteBits(guild->GetName().size(), 8); + data.WriteBit(guildGUID[0]); + data.WriteBits(guildSettings.GetComment().size(), 11); + data.WriteBit(guildGUID[4]); + data.WriteBit(guildGUID[1]); + data.WriteBit(guildGUID[2]); + data.WriteBit(guildGUID[6]); + data.WriteBit(guildGUID[3]); + + bufferData << uint32(guild->GetEmblemInfo().GetColor()); + bufferData << uint32(guild->GetEmblemInfo().GetBorderStyle()); // Guessed + bufferData << uint32(guild->GetEmblemInfo().GetStyle()); + + bufferData.WriteString(guildSettings.GetComment()); + + bufferData << uint8(0); // Unk + + bufferData.WriteByteSeq(guildGUID[5]); + + bufferData << uint32(guildSettings.GetInterests()); + + bufferData.WriteByteSeq(guildGUID[6]); + bufferData.WriteByteSeq(guildGUID[4]); + + bufferData << uint32(guild->GetLevel()); + + bufferData.WriteString(guild->GetName()); + + bufferData << uint32(guild->GetAchievementMgr().GetAchievementPoints()); + + bufferData.WriteByteSeq(guildGUID[7]); + + bufferData << uint8(sGuildFinderMgr->HasRequest(player->GetGUIDLow(), guild->GetGUID())); // Request pending + + bufferData.WriteByteSeq(guildGUID[2]); + bufferData.WriteByteSeq(guildGUID[0]); + + bufferData << uint32(guildSettings.GetAvailability()); + + bufferData.WriteByteSeq(guildGUID[1]); + + bufferData << uint32(guild->GetEmblemInfo().GetBackgroundColor()); + bufferData << uint32(0); // Unk Int 2 (+ 128) // Always 0 or 1 + bufferData << uint32(guild->GetEmblemInfo().GetBorderColor()); + bufferData << uint32(guildSettings.GetClassRoles()); + + bufferData.WriteByteSeq(guildGUID[3]); + bufferData << uint32(guild->GetMembersCount()); + } + + data.FlushBits(); + data.append(bufferData); + + player->SendDirectMessage(&data); +} + +void WorldSession::HandleGuildFinderDeclineRecruit(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_DECLINE_RECRUIT"); + + ObjectGuid playerGuid; + + playerGuid[1] = recvPacket.ReadBit(); + playerGuid[4] = recvPacket.ReadBit(); + playerGuid[5] = recvPacket.ReadBit(); + playerGuid[2] = recvPacket.ReadBit(); + playerGuid[6] = recvPacket.ReadBit(); + playerGuid[7] = recvPacket.ReadBit(); + playerGuid[0] = recvPacket.ReadBit(); + playerGuid[3] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(playerGuid[5]); + recvPacket.ReadByteSeq(playerGuid[7]); + recvPacket.ReadByteSeq(playerGuid[2]); + recvPacket.ReadByteSeq(playerGuid[3]); + recvPacket.ReadByteSeq(playerGuid[4]); + recvPacket.ReadByteSeq(playerGuid[1]); + recvPacket.ReadByteSeq(playerGuid[0]); + recvPacket.ReadByteSeq(playerGuid[6]); + + if (!IS_PLAYER_GUID(playerGuid)) + return; + + sGuildFinderMgr->RemoveMembershipRequest(GUID_LOPART(playerGuid), GetPlayer()->GetGuildId()); +} + +void WorldSession::HandleGuildFinderGetApplications(WorldPacket& /*recvPacket*/) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_GET_APPLICATIONS"); // Empty opcode + + std::list<MembershipRequest> applicatedGuilds = sGuildFinderMgr->GetAllMembershipRequestsForPlayer(GetPlayer()->GetGUIDLow()); + uint32 applicationsCount = applicatedGuilds.size(); + WorldPacket data(SMSG_LF_GUILD_MEMBERSHIP_LIST_UPDATED, 7 + 54 * applicationsCount); + data.WriteBits(applicationsCount, 20); + + if (applicationsCount > 0) + { + ByteBuffer bufferData(54 * applicationsCount); + for (std::list<MembershipRequest>::const_iterator itr = applicatedGuilds.begin(); itr != applicatedGuilds.end(); ++itr) + { + Guild* guild = sGuildMgr->GetGuildById(itr->GetGuildId()); + LFGuildSettings guildSettings = sGuildFinderMgr->GetGuildSettings(itr->GetGuildId()); + MembershipRequest request = *itr; + + ObjectGuid guildGuid = ObjectGuid(guild->GetGUID()); + + data.WriteBit(guildGuid[1]); + data.WriteBit(guildGuid[0]); + data.WriteBit(guildGuid[5]); + data.WriteBits(request.GetComment().size(), 11); + data.WriteBit(guildGuid[3]); + data.WriteBit(guildGuid[7]); + data.WriteBit(guildGuid[4]); + data.WriteBit(guildGuid[6]); + data.WriteBit(guildGuid[2]); + data.WriteBits(guild->GetName().size(), 8); + + bufferData.WriteByteSeq(guildGuid[2]); + bufferData.WriteString(request.GetComment()); + bufferData.WriteByteSeq(guildGuid[5]); + bufferData.WriteString(guild->GetName()); + + bufferData << uint32(guildSettings.GetAvailability()); + bufferData << uint32(request.GetExpiryTime() - time(NULL)); // Time left to application expiry (seconds) + + bufferData.WriteByteSeq(guildGuid[0]); + bufferData.WriteByteSeq(guildGuid[6]); + bufferData.WriteByteSeq(guildGuid[3]); + bufferData.WriteByteSeq(guildGuid[7]); + + bufferData << uint32(guildSettings.GetClassRoles()); + + bufferData.WriteByteSeq(guildGuid[4]); + bufferData.WriteByteSeq(guildGuid[1]); + + bufferData << uint32(time(NULL) - request.GetSubmitTime()); // Time since application (seconds) + bufferData << uint32(guildSettings.GetInterests()); + } + + data.FlushBits(); + data.append(bufferData); + } + data << uint32(10 - sGuildFinderMgr->CountRequestsFromPlayer(GetPlayer()->GetGUIDLow())); // Applications count left + + GetPlayer()->SendDirectMessage(&data); +} + +// Lists all recruits for a guild - Misses times +void WorldSession::HandleGuildFinderGetRecruits(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_GET_RECRUITS"); + + uint32 unkTime = 0; + recvPacket >> unkTime; + + Player* player = GetPlayer(); + if (!player->GetGuildId()) + return; + + std::vector<MembershipRequest> recruitsList = sGuildFinderMgr->GetAllMembershipRequestsForGuild(player->GetGuildId()); + uint32 recruitCount = recruitsList.size(); + + ByteBuffer dataBuffer(53 * recruitCount); + WorldPacket data(SMSG_LF_GUILD_RECRUIT_LIST_UPDATED, 7 + 26 * recruitCount + 53 * recruitCount); + data.WriteBits(recruitCount, 20); + + for (std::vector<MembershipRequest>::const_iterator itr = recruitsList.begin(); itr != recruitsList.end(); ++itr) + { + MembershipRequest request = *itr; + ObjectGuid playerGuid(MAKE_NEW_GUID(request.GetPlayerGUID(), 0, HIGHGUID_PLAYER)); + + data.WriteBits(request.GetComment().size(), 11); + data.WriteBit(playerGuid[2]); + data.WriteBit(playerGuid[4]); + data.WriteBit(playerGuid[3]); + data.WriteBit(playerGuid[7]); + data.WriteBit(playerGuid[0]); + data.WriteBits(request.GetName().size(), 7); + data.WriteBit(playerGuid[5]); + data.WriteBit(playerGuid[1]); + data.WriteBit(playerGuid[6]); + + dataBuffer.WriteByteSeq(playerGuid[4]); + + dataBuffer << int32(time(NULL) <= request.GetExpiryTime()); + + dataBuffer.WriteByteSeq(playerGuid[3]); + dataBuffer.WriteByteSeq(playerGuid[0]); + dataBuffer.WriteByteSeq(playerGuid[1]); + + dataBuffer << int32(request.GetLevel()); + + dataBuffer.WriteByteSeq(playerGuid[6]); + dataBuffer.WriteByteSeq(playerGuid[7]); + dataBuffer.WriteByteSeq(playerGuid[2]); + + dataBuffer << int32(time(NULL) - request.GetSubmitTime()); // Time in seconds since application submitted. + dataBuffer << int32(request.GetAvailability()); + dataBuffer << int32(request.GetClassRoles()); + dataBuffer << int32(request.GetInterests()); + dataBuffer << int32(request.GetExpiryTime() - time(NULL)); // TIme in seconds until application expires. + + dataBuffer.WriteString(request.GetName()); + dataBuffer.WriteString(request.GetComment()); + + dataBuffer << int32(request.GetClass()); + + dataBuffer.WriteByteSeq(playerGuid[5]); + } + + data.FlushBits(); + data.append(dataBuffer); + data << uint32(time(NULL)); // Unk time + + player->SendDirectMessage(&data); +} + +void WorldSession::HandleGuildFinderPostRequest(WorldPacket& /*recvPacket*/) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_POST_REQUEST"); // Empty opcode + + Player* player = GetPlayer(); + + if (!player->GetGuildId()) // Player must be in guild + return; + + bool isGuildMaster = true; + if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) + if (guild->GetLeaderGUID() != player->GetGUID()) + isGuildMaster = false; + + LFGuildSettings settings = sGuildFinderMgr->GetGuildSettings(player->GetGuildId()); + + WorldPacket data(SMSG_LF_GUILD_POST_UPDATED, 35); + data.WriteBit(isGuildMaster); // Guessed + + if (isGuildMaster) + { + data.WriteBit(settings.IsListed()); + data.WriteBits(settings.GetComment().size(), 11); + data << uint32(settings.GetLevel()); + data.WriteString(settings.GetComment()); + data << uint32(0); // Unk Int32 + data << uint32(settings.GetAvailability()); + data << uint32(settings.GetClassRoles()); + data << uint32(settings.GetInterests()); + } + else + data.FlushBits(); + player->SendDirectMessage(&data); +} + +void WorldSession::HandleGuildFinderRemoveRecruit(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_REMOVE_RECRUIT"); + + ObjectGuid guildGuid; + + guildGuid[0] = recvPacket.ReadBit(); + guildGuid[4] = recvPacket.ReadBit(); + guildGuid[3] = recvPacket.ReadBit(); + guildGuid[5] = recvPacket.ReadBit(); + guildGuid[7] = recvPacket.ReadBit(); + guildGuid[6] = recvPacket.ReadBit(); + guildGuid[2] = recvPacket.ReadBit(); + guildGuid[1] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guildGuid[4]); + recvPacket.ReadByteSeq(guildGuid[0]); + recvPacket.ReadByteSeq(guildGuid[3]); + recvPacket.ReadByteSeq(guildGuid[6]); + recvPacket.ReadByteSeq(guildGuid[5]); + recvPacket.ReadByteSeq(guildGuid[1]); + recvPacket.ReadByteSeq(guildGuid[2]); + recvPacket.ReadByteSeq(guildGuid[7]); + + if (!IS_GUILD_GUID(guildGuid)) + return; + + sGuildFinderMgr->RemoveMembershipRequest(GetPlayer()->GetGUIDLow(), GUID_LOPART(guildGuid)); +} + +// Sent any time a guild master sets an option in the interface and when listing / unlisting his guild +void WorldSession::HandleGuildFinderSetGuildPost(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_SET_GUILD_POST"); + + uint32 classRoles = 0; + uint32 availability = 0; + uint32 guildInterests = 0; + uint32 level = 0; + + recvPacket >> level >> availability >> guildInterests >> classRoles; + // Level sent is zero if untouched, force to any (from interface). Idk why + if (!level) + level = ANY_FINDER_LEVEL; + + uint16 length = recvPacket.ReadBits(11); + bool listed = recvPacket.ReadBit(); + std::string comment = recvPacket.ReadString(length); + + if (!(classRoles & GUILDFINDER_ALL_ROLES) || classRoles > GUILDFINDER_ALL_ROLES) + return; + if (!(availability & AVAILABILITY_ALWAYS) || availability > AVAILABILITY_ALWAYS) + return; + if (!(guildInterests & ALL_INTERESTS) || guildInterests > ALL_INTERESTS) + return; + if (!(level & ALL_GUILDFINDER_LEVELS) || level > ALL_GUILDFINDER_LEVELS) + return; + + Player* player = GetPlayer(); + + if (!player->GetGuildId()) // Player must be in guild + return; + + if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) // Player must be guild master + if (guild->GetLeaderGUID() != player->GetGUID()) + return; + + LFGuildSettings settings(listed, player->GetTeamId(), player->GetGuildId(), classRoles, availability, guildInterests, level, comment); + sGuildFinderMgr->SetGuildSettings(player->GetGuildId(), settings); +} diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp index b652192bfd7..a6e63d196c2 100644 --- a/src/server/game/Handlers/GuildHandler.cpp +++ b/src/server/game/Handlers/GuildHandler.cpp @@ -30,29 +30,21 @@ void WorldSession::HandleGuildQueryOpcode(WorldPacket& recvPacket) { - uint32 guildId; - recvPacket >> guildId; + uint64 guildGuid, playerGuid; + recvPacket >> guildGuid >> playerGuid; - TC_LOG_DEBUG("guild", "CMSG_GUILD_QUERY [%s]: Guild: %u", GetPlayerInfo().c_str(), guildId); - if (!guildId) - return; - - if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->HandleQuery(this); -} - -void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) -{ - std::string name; - recvPacket >> name; + TC_LOG_DEBUG("guild", "CMSG_GUILD_QUERY [%s]: Guild: %u Target: %u", + GetPlayerInfo().c_str(), GUID_LOPART(guildGuid), GUID_LOPART(playerGuid)); - TC_LOG_ERROR("guild", "CMSG_GUILD_CREATE: Possible hacking-attempt: %s tried to create a guild [Name: %s] using cheats", GetPlayerInfo().c_str(), name.c_str()); + if (Guild* guild = sGuildMgr->GetGuildByGuid(guildGuid)) + if (guild->IsMember(playerGuid)) + guild->HandleQuery(this); } void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) { - std::string invitedName; - recvPacket >> invitedName; + uint32 nameLength = recvPacket.ReadBits(7); + std::string invitedName = recvPacket.ReadString(nameLength); TC_LOG_DEBUG("guild", "CMSG_GUILD_INVITE [%s]: Invited: %s", GetPlayerInfo().c_str(), invitedName.c_str()); if (normalizePlayerName(invitedName)) @@ -62,19 +54,35 @@ void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) { - std::string playerName; - recvPacket >> playerName; + ObjectGuid playerGuid; - TC_LOG_DEBUG("guild", "CMSG_GUILD_REMOVE [%s]: Target: %s", GetPlayerInfo().c_str(), playerName.c_str()); + playerGuid[6] = recvPacket.ReadBit(); + playerGuid[5] = recvPacket.ReadBit(); + playerGuid[4] = recvPacket.ReadBit(); + playerGuid[0] = recvPacket.ReadBit(); + playerGuid[1] = recvPacket.ReadBit(); + playerGuid[3] = recvPacket.ReadBit(); + playerGuid[7] = recvPacket.ReadBit(); + playerGuid[2] = recvPacket.ReadBit(); - if (normalizePlayerName(playerName)) - if (Guild* guild = GetPlayer()->GetGuild()) - guild->HandleRemoveMember(this, playerName); + recvPacket.ReadByteSeq(playerGuid[2]); + recvPacket.ReadByteSeq(playerGuid[6]); + recvPacket.ReadByteSeq(playerGuid[5]); + recvPacket.ReadByteSeq(playerGuid[7]); + recvPacket.ReadByteSeq(playerGuid[1]); + recvPacket.ReadByteSeq(playerGuid[4]); + recvPacket.ReadByteSeq(playerGuid[3]); + recvPacket.ReadByteSeq(playerGuid[0]); + + TC_LOG_DEBUG("guild", "CMSG_GUILD_REMOVE [%s]: Target: %u", GetPlayerInfo().c_str(), GUID_LOPART(playerGuid)); + + if (Guild* guild = GetPlayer()->GetGuild()) + guild->HandleRemoveMember(this, playerGuid); } void WorldSession::HandleGuildAcceptOpcode(WorldPacket& /*recvPacket*/) { - TC_LOG_DEBUG("guild", "CMSG_GUILD_ACCEPT [%s]", GetPlayer()->GetName().c_str()); + TC_LOG_DEBUG("guild", "CMSG_GUILD_ACCEPT [%s]", GetPlayerInfo().c_str()); if (!GetPlayer()->GetGuildId()) if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildIdInvited())) @@ -89,17 +97,10 @@ void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) GetPlayer()->SetInGuild(0); } -void WorldSession::HandleGuildInfoOpcode(WorldPacket& /*recvPacket*/) -{ - TC_LOG_DEBUG("guild", "CMSG_GUILD_INFO [%s]", GetPlayerInfo().c_str()); - - if (Guild* guild = GetPlayer()->GetGuild()) - guild->SendInfo(this); -} - -void WorldSession::HandleGuildRosterOpcode(WorldPacket& /*recvPacket*/) +void WorldSession::HandleGuildRosterOpcode(WorldPacket& recvPacket) { TC_LOG_DEBUG("guild", "CMSG_GUILD_ROSTER [%s]", GetPlayerInfo().c_str()); + recvPacket.rfinish(); if (Guild* guild = GetPlayer()->GetGuild()) guild->HandleRoster(this); @@ -109,26 +110,107 @@ void WorldSession::HandleGuildRosterOpcode(WorldPacket& /*recvPacket*/) void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) { - std::string playerName; - recvPacket >> playerName; + ObjectGuid targetGuid; - TC_LOG_DEBUG("guild", "CMSG_GUILD_PROMOTE [%s]: Target: %s", GetPlayerInfo().c_str(), playerName.c_str()); + targetGuid[7] = recvPacket.ReadBit(); + targetGuid[2] = recvPacket.ReadBit(); + targetGuid[5] = recvPacket.ReadBit(); + targetGuid[6] = recvPacket.ReadBit(); + targetGuid[1] = recvPacket.ReadBit(); + targetGuid[0] = recvPacket.ReadBit(); + targetGuid[3] = recvPacket.ReadBit(); + targetGuid[4] = recvPacket.ReadBit(); - if (normalizePlayerName(playerName)) - if (Guild* guild = GetPlayer()->GetGuild()) - guild->HandleUpdateMemberRank(this, playerName, false); + recvPacket.ReadByteSeq(targetGuid[0]); + recvPacket.ReadByteSeq(targetGuid[5]); + recvPacket.ReadByteSeq(targetGuid[2]); + recvPacket.ReadByteSeq(targetGuid[3]); + recvPacket.ReadByteSeq(targetGuid[6]); + recvPacket.ReadByteSeq(targetGuid[4]); + recvPacket.ReadByteSeq(targetGuid[1]); + recvPacket.ReadByteSeq(targetGuid[7]); + + TC_LOG_DEBUG("guild", "CMSG_GUILD_PROMOTE [%s]: Target: %u", GetPlayerInfo().c_str(), GUID_LOPART(targetGuid)); + + if (Guild* guild = GetPlayer()->GetGuild()) + guild->HandleUpdateMemberRank(this, targetGuid, false); } void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket) { - std::string playerName; - recvPacket >> playerName; + ObjectGuid targetGuid; - TC_LOG_DEBUG("guild", "CMSG_GUILD_DEMOTE [%s]: Target: %s", GetPlayerInfo().c_str(), playerName.c_str()); + targetGuid[7] = recvPacket.ReadBit(); + targetGuid[1] = recvPacket.ReadBit(); + targetGuid[5] = recvPacket.ReadBit(); + targetGuid[6] = recvPacket.ReadBit(); + targetGuid[2] = recvPacket.ReadBit(); + targetGuid[3] = recvPacket.ReadBit(); + targetGuid[0] = recvPacket.ReadBit(); + targetGuid[4] = recvPacket.ReadBit(); - if (normalizePlayerName(playerName)) - if (Guild* guild = GetPlayer()->GetGuild()) - guild->HandleUpdateMemberRank(this, playerName, true); + recvPacket.ReadByteSeq(targetGuid[1]); + recvPacket.ReadByteSeq(targetGuid[2]); + recvPacket.ReadByteSeq(targetGuid[7]); + recvPacket.ReadByteSeq(targetGuid[5]); + recvPacket.ReadByteSeq(targetGuid[6]); + recvPacket.ReadByteSeq(targetGuid[0]); + recvPacket.ReadByteSeq(targetGuid[4]); + recvPacket.ReadByteSeq(targetGuid[3]); + + TC_LOG_DEBUG("guild", "CMSG_GUILD_DEMOTE [%s]: Target: %u", GetPlayerInfo().c_str(), GUID_LOPART(targetGuid)); + + if (Guild* guild = GetPlayer()->GetGuild()) + guild->HandleUpdateMemberRank(this, targetGuid, true); +} + +void WorldSession::HandleGuildAssignRankOpcode(WorldPacket& recvPacket) +{ + ObjectGuid targetGuid; + ObjectGuid setterGuid; + + uint32 rankId; + recvPacket >> rankId; + + targetGuid[1] = recvPacket.ReadBit(); + targetGuid[7] = recvPacket.ReadBit(); + setterGuid[4] = recvPacket.ReadBit(); + setterGuid[2] = recvPacket.ReadBit(); + targetGuid[4] = recvPacket.ReadBit(); + targetGuid[5] = recvPacket.ReadBit(); + targetGuid[6] = recvPacket.ReadBit(); + setterGuid[1] = recvPacket.ReadBit(); + setterGuid[7] = recvPacket.ReadBit(); + targetGuid[2] = recvPacket.ReadBit(); + targetGuid[3] = recvPacket.ReadBit(); + targetGuid[0] = recvPacket.ReadBit(); + setterGuid[6] = recvPacket.ReadBit(); + setterGuid[3] = recvPacket.ReadBit(); + setterGuid[0] = recvPacket.ReadBit(); + setterGuid[5] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(targetGuid[0]); + recvPacket.ReadByteSeq(setterGuid[1]); + recvPacket.ReadByteSeq(setterGuid[3]); + recvPacket.ReadByteSeq(setterGuid[5]); + recvPacket.ReadByteSeq(targetGuid[7]); + recvPacket.ReadByteSeq(targetGuid[3]); + recvPacket.ReadByteSeq(setterGuid[0]); + recvPacket.ReadByteSeq(targetGuid[1]); + recvPacket.ReadByteSeq(setterGuid[6]); + recvPacket.ReadByteSeq(targetGuid[2]); + recvPacket.ReadByteSeq(targetGuid[5]); + recvPacket.ReadByteSeq(targetGuid[4]); + recvPacket.ReadByteSeq(setterGuid[2]); + recvPacket.ReadByteSeq(setterGuid[4]); + recvPacket.ReadByteSeq(targetGuid[6]); + recvPacket.ReadByteSeq(setterGuid[7]); + + TC_LOG_DEBUG("guild", "CMSG_GUILD_ASSIGN_MEMBER_RANK [%s]: Target: %u Rank: %u, Issuer: %u", + GetPlayerInfo().c_str(), GUID_LOPART(targetGuid), rankId, GUID_LOPART(setterGuid)); + + if (Guild* guild = GetPlayer()->GetGuild()) + guild->HandleSetMemberRank(this, targetGuid, setterGuid, rankId); } void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) @@ -147,100 +229,85 @@ void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) guild->HandleDisband(this); } -void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) -{ - std::string name; - recvPacket >> name; - - TC_LOG_DEBUG("guild", "CMSG_GUILD_LEADER [%s]: Target: %s", GetPlayerInfo().c_str(), name.c_str()); - - if (normalizePlayerName(name)) - if (Guild* guild = GetPlayer()->GetGuild()) - guild->HandleSetLeader(this, name); -} - void WorldSession::HandleGuildMOTDOpcode(WorldPacket& recvPacket) { - std::string motd; - recvPacket >> motd; - + uint32 motdLength = recvPacket.ReadBits(11); + std::string motd = recvPacket.ReadString(motdLength); TC_LOG_DEBUG("guild", "CMSG_GUILD_MOTD [%s]: MOTD: %s", GetPlayerInfo().c_str(), motd.c_str()); if (Guild* guild = GetPlayer()->GetGuild()) guild->HandleSetMOTD(this, motd); } -void WorldSession::HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket) +void WorldSession::HandleGuildSetNoteOpcode(WorldPacket& recvPacket) { - std::string playerName; - std::string note; - recvPacket >> playerName >> note; + ObjectGuid playerGuid; - TC_LOG_DEBUG("guild", "CMSG_GUILD_SET_PUBLIC_NOTE [%s]: Target: %s, Note: %s", - GetPlayerInfo().c_str(), playerName.c_str(), note.c_str()); - - if (normalizePlayerName(playerName)) - if (Guild* guild = GetPlayer()->GetGuild()) - guild->HandleSetMemberNote(this, playerName, note, true); -} + playerGuid[1] = recvPacket.ReadBit(); + playerGuid[4] = recvPacket.ReadBit(); + playerGuid[5] = recvPacket.ReadBit(); + playerGuid[3] = recvPacket.ReadBit(); + playerGuid[0] = recvPacket.ReadBit(); + playerGuid[7] = recvPacket.ReadBit(); + bool ispublic = recvPacket.ReadBit(); // 0 == Officer, 1 == Public + playerGuid[6] = recvPacket.ReadBit(); + uint32 noteLength = recvPacket.ReadBits(8); + playerGuid[2] = recvPacket.ReadBit(); -void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) -{ - std::string playerName; - std::string note; - recvPacket >> playerName >> note; + recvPacket.ReadByteSeq(playerGuid[4]); + recvPacket.ReadByteSeq(playerGuid[5]); + recvPacket.ReadByteSeq(playerGuid[0]); + recvPacket.ReadByteSeq(playerGuid[3]); + recvPacket.ReadByteSeq(playerGuid[1]); + recvPacket.ReadByteSeq(playerGuid[6]); + recvPacket.ReadByteSeq(playerGuid[7]); + std::string note = recvPacket.ReadString(noteLength); + recvPacket.ReadByteSeq(playerGuid[2]); - TC_LOG_DEBUG("guild", "CMSG_GUILD_SET_OFFICER_NOTE [%s]: Target: %s, Note: %s", - GetPlayerInfo().c_str(), playerName.c_str(), note.c_str()); + TC_LOG_DEBUG("guild", "CMSG_GUILD_SET_NOTE [%s]: Target: %u, Note: %s, Public: %u", + GetPlayerInfo().c_str(), GUID_LOPART(playerGuid), note.c_str(), ispublic); - if (normalizePlayerName(playerName)) - if (Guild* guild = GetPlayer()->GetGuild()) - guild->HandleSetMemberNote(this, playerName, note, false); + if (Guild* guild = GetPlayer()->GetGuild()) + guild->HandleSetMemberNote(this, note, playerGuid, ispublic); } -void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket) +void WorldSession::HandleGuildQueryRanksOpcode(WorldPacket& recvPacket) { - uint32 rankId; - recvPacket >> rankId; - - uint32 rights; - recvPacket >> rights; - - std::string rankName; - recvPacket >> rankName; - - uint32 money; - recvPacket >> money; - - TC_LOG_DEBUG("guild", "CMSG_GUILD_RANK [%s]: Rank: %s (%u)", GetPlayerInfo().c_str(), rankName.c_str(), rankId); + ObjectGuid guildGuid; - Guild* guild = GetPlayer()->GetGuild(); - if (!guild) - { - recvPacket.rpos(recvPacket.wpos()); - return; - } - - GuildBankRightsAndSlotsVec rightsAndSlots(GUILD_BANK_MAX_TABS); - - for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) - { - uint32 bankRights; - uint32 slots; + guildGuid[2] = recvPacket.ReadBit(); + guildGuid[3] = recvPacket.ReadBit(); + guildGuid[0] = recvPacket.ReadBit(); + guildGuid[6] = recvPacket.ReadBit(); + guildGuid[4] = recvPacket.ReadBit(); + guildGuid[7] = recvPacket.ReadBit(); + guildGuid[5] = recvPacket.ReadBit(); + guildGuid[1] = recvPacket.ReadBit(); - recvPacket >> bankRights; - recvPacket >> slots; + recvPacket.ReadByteSeq(guildGuid[3]); + recvPacket.ReadByteSeq(guildGuid[4]); + recvPacket.ReadByteSeq(guildGuid[5]); + recvPacket.ReadByteSeq(guildGuid[7]); + recvPacket.ReadByteSeq(guildGuid[1]); + recvPacket.ReadByteSeq(guildGuid[0]); + recvPacket.ReadByteSeq(guildGuid[6]); + recvPacket.ReadByteSeq(guildGuid[2]); - rightsAndSlots[tabId] = GuildBankRightsAndSlots(tabId, bankRights, slots); - } + TC_LOG_DEBUG("guild", "CMSG_GUILD_QUERY_RANKS [%s]: Guild: %u", + GetPlayerInfo().c_str(), GUID_LOPART(guildGuid)); - guild->HandleSetRankInfo(this, rankId, rankName, rights, money, rightsAndSlots); + if (Guild* guild = sGuildMgr->GetGuildByGuid(guildGuid)) + if (guild->IsMember(_player->GetGUID())) + guild->SendGuildRankInfo(this); } void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) { - std::string rankName; - recvPacket >> rankName; + uint32 rankId; + recvPacket >> rankId; + + uint32 length = recvPacket.ReadBits(7); + std::string rankName = recvPacket.ReadString(length); TC_LOG_DEBUG("guild", "CMSG_GUILD_ADD_RANK [%s]: Rank: %s", GetPlayerInfo().c_str(), rankName.c_str()); @@ -248,18 +315,21 @@ void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) guild->HandleAddNewRank(this, rankName); } -void WorldSession::HandleGuildDelRankOpcode(WorldPacket& /*recvPacket*/) +void WorldSession::HandleGuildDelRankOpcode(WorldPacket& recvPacket) { - TC_LOG_DEBUG("guild", "CMSG_GUILD_DEL_RANK [%s]", GetPlayerInfo().c_str()); + uint32 rankId; + recvPacket >> rankId; + + TC_LOG_DEBUG("guild", "CMSG_GUILD_DEL_RANK [%s]: Rank: %u", GetPlayerInfo().c_str(), rankId); if (Guild* guild = GetPlayer()->GetGuild()) - guild->HandleRemoveLowestRank(this); + guild->HandleRemoveRank(this, rankId); } void WorldSession::HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket) { - std::string info; - recvPacket >> info; + uint32 length = recvPacket.ReadBits(12); + std::string info = recvPacket.ReadString(length); TC_LOG_DEBUG("guild", "CMSG_GUILD_INFO_TEXT [%s]: %s", GetPlayerInfo().c_str(), info.c_str()); @@ -304,32 +374,36 @@ void WorldSession::HandleGuildEventLogQueryOpcode(WorldPacket& /* recvPacket */) guild->SendEventLog(this); } -void WorldSession::HandleGuildBankMoneyWithdrawn(WorldPacket & /* recvData */) +void WorldSession::HandleGuildBankMoneyWithdrawn(WorldPacket& /* recvPacket */) { - TC_LOG_DEBUG("guild", "MSG_GUILD_BANK_MONEY_WITHDRAWN [%s]", GetPlayerInfo().c_str()); + TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_MONEY_WITHDRAWN [%s]", GetPlayerInfo().c_str()); if (Guild* guild = GetPlayer()->GetGuild()) guild->SendMoneyInfo(this); } -void WorldSession::HandleGuildPermissions(WorldPacket& /* recvData */) +void WorldSession::HandleGuildPermissions(WorldPacket& /* recvPacket */) { - TC_LOG_DEBUG("guild", "MSG_GUILD_PERMISSIONS [%s]", GetPlayerInfo().c_str()); + TC_LOG_DEBUG("guild", "CMSG_GUILD_PERMISSIONS [%s]", GetPlayerInfo().c_str()); if (Guild* guild = GetPlayer()->GetGuild()) guild->SendPermissions(this); } // Called when clicking on Guild bank gameobject -void WorldSession::HandleGuildBankerActivate(WorldPacket& recvData) +void WorldSession::HandleGuildBankerActivate(WorldPacket& recvPacket) { uint64 guid; bool sendAllSlots; - recvData >> guid >> sendAllSlots; + recvPacket >> guid >> sendAllSlots; TC_LOG_DEBUG("guild", "CMSG_GUILD_BANKER_ACTIVATE [%s]: Go: [" UI64FMTD "] AllSlots: %u" , GetPlayerInfo().c_str(), guid, sendAllSlots); + GameObject const* const go = GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_GUILD_BANK); + if (!go) + return; + Guild* const guild = GetPlayer()->GetGuild(); if (!guild) { @@ -337,33 +411,33 @@ void WorldSession::HandleGuildBankerActivate(WorldPacket& recvData) return; } - guild->SendBankTabsInfo(this, sendAllSlots); + guild->SendBankList(this, 0, true, true); } // Called when opening guild bank tab only (first one) -void WorldSession::HandleGuildBankQueryTab(WorldPacket& recvData) +void WorldSession::HandleGuildBankQueryTab(WorldPacket& recvPacket) { uint64 guid; uint8 tabId; - bool full; + bool sendAllSlots; - recvData >> guid >> tabId >> full; + recvPacket >> guid >> tabId >> sendAllSlots; - TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_QUERY_TAB [%s]: Go: [" UI64FMTD "], TabId: %u, ShowTabs: %u" - , GetPlayerInfo().c_str(), guid, tabId, full); + TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_QUERY_TAB [%s]: Go: [" UI64FMTD "], TabId: %u, AllSlots: %u" + , GetPlayerInfo().c_str(), guid, tabId, sendAllSlots); if (GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_GUILD_BANK)) if (Guild* guild = GetPlayer()->GetGuild()) - guild->SendBankTabData(this, tabId); + guild->SendBankList(this, tabId, true, false); } -void WorldSession::HandleGuildBankDepositMoney(WorldPacket& recvData) +void WorldSession::HandleGuildBankDepositMoney(WorldPacket& recvPacket) { uint64 guid; - uint32 money; - recvData >> guid >> money; + uint64 money; + recvPacket >> guid >> money; - TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_DEPOSIT_MONEY [%s]: Go: [" UI64FMTD "], money: %u", + TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_DEPOSIT_MONEY [%s]: Go: [" UI64FMTD "], money: " UI64FMTD, GetPlayerInfo().c_str(), guid, money); if (GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_GUILD_BANK)) @@ -372,13 +446,13 @@ void WorldSession::HandleGuildBankDepositMoney(WorldPacket& recvData) guild->HandleMemberDepositMoney(this, money); } -void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket& recvData) +void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket& recvPacket) { uint64 guid; - uint32 money; - recvData >> guid >> money; + uint64 money; + recvPacket >> guid >> money; - TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_WITHDRAW_MONEY [%s]: Go: [" UI64FMTD "], money: %u", + TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_WITHDRAW_MONEY [%s]: Go: [" UI64FMTD "], money: " UI64FMTD, GetPlayerInfo().c_str(), guid, money); if (money && GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_GUILD_BANK)) @@ -386,28 +460,28 @@ void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket& recvData) guild->HandleMemberWithdrawMoney(this, money); } -void WorldSession::HandleGuildBankSwapItems(WorldPacket& recvData) +void WorldSession::HandleGuildBankSwapItems(WorldPacket& recvPacket) { TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_SWAP_ITEMS [%s]", GetPlayerInfo().c_str()); uint64 GoGuid; - recvData >> GoGuid; + recvPacket >> GoGuid; if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) { - recvData.rfinish(); // Prevent additional spam at rejected packet + recvPacket.rfinish(); // Prevent additional spam at rejected packet return; } Guild* guild = GetPlayer()->GetGuild(); if (!guild) { - recvData.rfinish(); // Prevent additional spam at rejected packet + recvPacket.rfinish(); // Prevent additional spam at rejected packet return; } uint8 bankToBank; - recvData >> bankToBank; + recvPacket >> bankToBank; uint8 tabId; uint8 slotId; @@ -417,18 +491,19 @@ void WorldSession::HandleGuildBankSwapItems(WorldPacket& recvData) if (bankToBank) { uint8 destTabId; - recvData >> destTabId; + recvPacket >> destTabId; uint8 destSlotId; - recvData >> destSlotId; - recvData.read_skip<uint32>(); // Always 0 + recvPacket >> destSlotId; - recvData >> tabId; - recvData >> slotId; - recvData >> itemEntry; - recvData.read_skip<uint8>(); // Always 0 + uint32 destItemEntry; + recvPacket >> destItemEntry; - recvData >> splitedAmount; + recvPacket >> tabId; + recvPacket >> slotId; + recvPacket >> itemEntry; + recvPacket.read_skip<uint8>(); // Always 0 + recvPacket >> splitedAmount; guild->SwapItems(GetPlayer(), tabId, slotId, destTabId, destSlotId, splitedAmount); } @@ -438,97 +513,313 @@ void WorldSession::HandleGuildBankSwapItems(WorldPacket& recvData) uint8 playerSlotId = NULL_SLOT; uint8 toChar = 1; - recvData >> tabId; - recvData >> slotId; - recvData >> itemEntry; + recvPacket >> tabId; + recvPacket >> slotId; + recvPacket >> itemEntry; uint8 autoStore; - recvData >> autoStore; + recvPacket >> autoStore; if (autoStore) { - recvData.read_skip<uint32>(); // autoStoreCount - recvData.read_skip<uint8>(); // ToChar (?), always and expected to be 1 (autostore only triggered in Bank -> Char) - recvData.read_skip<uint32>(); // Always 0 + recvPacket.read_skip<uint32>(); // autoStoreCount + recvPacket.read_skip<uint8>(); // ToChar (?), always and expected to be 1 (autostore only triggered in Bank -> Char) + recvPacket.read_skip<uint32>(); // Always 0 } else { - recvData >> playerBag; - recvData >> playerSlotId; - recvData >> toChar; - recvData >> splitedAmount; + recvPacket >> playerBag; + recvPacket >> playerSlotId; + recvPacket >> toChar; + recvPacket >> splitedAmount; } // Player <-> Bank // Allow to work with inventory only if (!Player::IsInventoryPos(playerBag, playerSlotId) && !(playerBag == NULL_BAG && playerSlotId == NULL_SLOT)) - GetPlayer()->SendEquipError(EQUIP_ERR_NONE, NULL); + GetPlayer()->SendEquipError(EQUIP_ERR_INTERNAL_BAG_ERROR, NULL); else guild->SwapItemsWithInventory(GetPlayer(), toChar != 0, tabId, slotId, playerBag, playerSlotId, splitedAmount); } } -void WorldSession::HandleGuildBankBuyTab(WorldPacket& recvData) +void WorldSession::HandleGuildBankBuyTab(WorldPacket& recvPacket) { uint64 guid; - uint8 tabId; + recvPacket >> guid; - recvData >> guid >> tabId; + uint8 tabId; + recvPacket >> tabId; TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_BUY_TAB [%s]: Go: [" UI64FMTD "], TabId: %u", GetPlayerInfo().c_str(), guid, tabId); - - if (GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (!guid || GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_GUILD_BANK)) if (Guild* guild = GetPlayer()->GetGuild()) guild->HandleBuyBankTab(this, tabId); } -void WorldSession::HandleGuildBankUpdateTab(WorldPacket& recvData) +void WorldSession::HandleGuildBankUpdateTab(WorldPacket& recvPacket) { uint64 guid; uint8 tabId; std::string name, icon; - recvData >> guid >> tabId >> name >> icon; + recvPacket >> guid >> tabId >> name >> icon; TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_UPDATE_TAB [%s]: Go: [" UI64FMTD "], TabId: %u, Name: %s, Icon: %s" , GetPlayerInfo().c_str(), guid, tabId, name.c_str(), icon.c_str()); - if (!name.empty() && !icon.empty()) if (GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_GUILD_BANK)) if (Guild* guild = GetPlayer()->GetGuild()) guild->HandleSetBankTabInfo(this, tabId, name, icon); } -void WorldSession::HandleGuildBankLogQuery(WorldPacket& recvData) +void WorldSession::HandleGuildBankLogQuery(WorldPacket& recvPacket) { - uint8 tabId; - recvData >> tabId; + uint32 tabId; + recvPacket >> tabId; - TC_LOG_DEBUG("guild", "MSG_GUILD_BANK_LOG_QUERY [%s]: TabId: %u", GetPlayerInfo().c_str(), tabId); + TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_LOG_QUERY [%s]: TabId: %u", GetPlayerInfo().c_str(), tabId); if (Guild* guild = GetPlayer()->GetGuild()) guild->SendBankLog(this, tabId); } -void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recvData) +void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recvPacket) { uint8 tabId; - recvData >> tabId; + recvPacket >> tabId; - TC_LOG_DEBUG("guild", "MSG_QUERY_GUILD_BANK_TEXT [%s]: TabId: %u", GetPlayerInfo().c_str(), tabId); + TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_QUERY_TEXT [%s]: TabId: %u", GetPlayerInfo().c_str(), tabId); if (Guild* guild = GetPlayer()->GetGuild()) guild->SendBankTabText(this, tabId); } -void WorldSession::HandleSetGuildBankTabText(WorldPacket &recvData) +void WorldSession::HandleSetGuildBankTabText(WorldPacket& recvPacket) { - uint8 tabId; - std::string text; - recvData >> tabId >> text; + uint32 tabId; + recvPacket >> tabId; + + uint32 textLen = recvPacket.ReadBits(14); + std::string text = recvPacket.ReadString(textLen); TC_LOG_DEBUG("guild", "CMSG_SET_GUILD_BANK_TEXT [%s]: TabId: %u, Text: %s", GetPlayerInfo().c_str(), tabId, text.c_str()); if (Guild* guild = GetPlayer()->GetGuild()) guild->SetBankTabText(tabId, text); } + +void WorldSession::HandleGuildQueryXPOpcode(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUERY_GUILD_XP"); + + ObjectGuid guildGuid; + + guildGuid[2] = recvPacket.ReadBit(); + guildGuid[1] = recvPacket.ReadBit(); + guildGuid[0] = recvPacket.ReadBit(); + guildGuid[5] = recvPacket.ReadBit(); + guildGuid[4] = recvPacket.ReadBit(); + guildGuid[7] = recvPacket.ReadBit(); + guildGuid[6] = recvPacket.ReadBit(); + guildGuid[3] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guildGuid[7]); + recvPacket.ReadByteSeq(guildGuid[2]); + recvPacket.ReadByteSeq(guildGuid[3]); + recvPacket.ReadByteSeq(guildGuid[6]); + recvPacket.ReadByteSeq(guildGuid[1]); + recvPacket.ReadByteSeq(guildGuid[5]); + recvPacket.ReadByteSeq(guildGuid[0]); + recvPacket.ReadByteSeq(guildGuid[4]); + + TC_LOG_DEBUG("guild", "CMSG_QUERY_GUILD_XP [%s]: Guild: %u", GetPlayerInfo().c_str(), GUID_LOPART(guildGuid)); + + if (Guild* guild = sGuildMgr->GetGuildByGuid(guildGuid)) + if (guild->IsMember(_player->GetGUID())) + guild->SendGuildXP(this); +} + +void WorldSession::HandleGuildSetRankPermissionsOpcode(WorldPacket& recvPacket) +{ + Guild* guild = GetPlayer()->GetGuild(); + if (!guild) + { + recvPacket.rfinish(); + return; + } + + uint32 oldRankId; + uint32 newRankId; + uint32 oldRights; + uint32 newRights; + uint32 moneyPerDay; + + recvPacket >> oldRankId; + recvPacket >> oldRights; + recvPacket >> newRights; + + GuildBankRightsAndSlotsVec rightsAndSlots(GUILD_BANK_MAX_TABS); + for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) + { + uint32 bankRights; + uint32 slots; + + recvPacket >> bankRights; + recvPacket >> slots; + + rightsAndSlots[tabId] = GuildBankRightsAndSlots(tabId, uint8(bankRights), slots); + } + + recvPacket >> moneyPerDay; + recvPacket >> newRankId; + uint32 nameLength = recvPacket.ReadBits(7); + std::string rankName = recvPacket.ReadString(nameLength); + + TC_LOG_DEBUG("guild", "CMSG_GUILD_SET_RANK_PERMISSIONS [%s]: Rank: %s (%u)", GetPlayerInfo().c_str(), rankName.c_str(), newRankId); + + guild->HandleSetRankInfo(this, newRankId, rankName, newRights, moneyPerDay, rightsAndSlots); +} + +void WorldSession::HandleGuildRequestPartyState(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_GUILD_REQUEST_PARTY_STATE"); + + ObjectGuid guildGuid; + + guildGuid[0] = recvPacket.ReadBit(); + guildGuid[6] = recvPacket.ReadBit(); + guildGuid[7] = recvPacket.ReadBit(); + guildGuid[3] = recvPacket.ReadBit(); + guildGuid[5] = recvPacket.ReadBit(); + guildGuid[1] = recvPacket.ReadBit(); + guildGuid[2] = recvPacket.ReadBit(); + guildGuid[4] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guildGuid[6]); + recvPacket.ReadByteSeq(guildGuid[3]); + recvPacket.ReadByteSeq(guildGuid[2]); + recvPacket.ReadByteSeq(guildGuid[1]); + recvPacket.ReadByteSeq(guildGuid[5]); + recvPacket.ReadByteSeq(guildGuid[0]); + recvPacket.ReadByteSeq(guildGuid[7]); + recvPacket.ReadByteSeq(guildGuid[4]); + + if (Guild* guild = sGuildMgr->GetGuildByGuid(guildGuid)) + guild->HandleGuildPartyRequest(this); +} + +void WorldSession::HandleGuildRequestMaxDailyXP(WorldPacket& recvPacket) +{ + ObjectGuid guid; + guid[0] = recvPacket.ReadBit(); + guid[3] = recvPacket.ReadBit(); + guid[5] = recvPacket.ReadBit(); + guid[1] = recvPacket.ReadBit(); + guid[4] = recvPacket.ReadBit(); + guid[6] = recvPacket.ReadBit(); + guid[7] = recvPacket.ReadBit(); + guid[2] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guid[7]); + recvPacket.ReadByteSeq(guid[4]); + recvPacket.ReadByteSeq(guid[3]); + recvPacket.ReadByteSeq(guid[5]); + recvPacket.ReadByteSeq(guid[1]); + recvPacket.ReadByteSeq(guid[2]); + recvPacket.ReadByteSeq(guid[6]); + recvPacket.ReadByteSeq(guid[0]); + + if (Guild* guild = sGuildMgr->GetGuildByGuid(guid)) + { + if (guild->IsMember(_player->GetGUID())) + { + WorldPacket data(SMSG_GUILD_MAX_DAILY_XP, 8); + data << uint64(sWorld->getIntConfig(CONFIG_GUILD_DAILY_XP_CAP)); + SendPacket(&data); + } + } +} + +void WorldSession::HandleAutoDeclineGuildInvites(WorldPacket& recvPacket) +{ + uint8 enable; + recvPacket >> enable; + + GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_AUTO_DECLINE_GUILD, enable != 0); +} + +void WorldSession::HandleGuildRewardsQueryOpcode(WorldPacket& recvPacket) +{ + recvPacket.read_skip<uint32>(); // Unk + + if (sGuildMgr->GetGuildById(_player->GetGuildId())) + { + std::vector<GuildReward> const& rewards = sGuildMgr->GetGuildRewards(); + + WorldPacket data(SMSG_GUILD_REWARDS_LIST, 3 + rewards.size() * (4 + 4 + 4 + 8 + 4 + 4)); + data.WriteBits(rewards.size(), 21); + data.FlushBits(); + + for (uint32 i = 0; i < rewards.size(); i++) + { + data << uint32(rewards[i].Standing); + data << int32(rewards[i].Racemask); + data << uint32(rewards[i].Entry); + data << uint64(rewards[i].Price); + data << uint32(0); // Unused + data << uint32(rewards[i].AchievementId); + } + data << uint32(time(NULL)); + SendPacket(&data); + } +} + +void WorldSession::HandleGuildQueryNewsOpcode(WorldPacket& recvPacket) +{ + recvPacket.read_skip<uint32>(); + TC_LOG_DEBUG("guild", "CMSG_GUILD_QUERY_NEWS [%s]", GetPlayerInfo().c_str()); + if (Guild* guild = GetPlayer()->GetGuild()) + guild->SendNewsUpdate(this); +} + +void WorldSession::HandleGuildNewsUpdateStickyOpcode(WorldPacket& recvPacket) +{ + uint32 newsId; + bool sticky; + ObjectGuid guid; + + recvPacket >> newsId; + + guid[2] = recvPacket.ReadBit(); + guid[4] = recvPacket.ReadBit(); + guid[3] = recvPacket.ReadBit(); + guid[0] = recvPacket.ReadBit(); + sticky = recvPacket.ReadBit(); + guid[6] = recvPacket.ReadBit(); + guid[7] = recvPacket.ReadBit(); + guid[1] = recvPacket.ReadBit(); + guid[5] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guid[6]); + recvPacket.ReadByteSeq(guid[2]); + recvPacket.ReadByteSeq(guid[1]); + recvPacket.ReadByteSeq(guid[0]); + recvPacket.ReadByteSeq(guid[5]); + recvPacket.ReadByteSeq(guid[3]); + recvPacket.ReadByteSeq(guid[7]); + recvPacket.ReadByteSeq(guid[4]); + + if (Guild* guild = GetPlayer()->GetGuild()) + guild->HandleNewsSetSticky(this, newsId, sticky); +} + +void WorldSession::HandleGuildSetGuildMaster(WorldPacket& recvPacket) +{ + uint8 nameLength = recvPacket.ReadBits(7); + // This is related to guild master inactivity. + /*bool isDethrone = */recvPacket.ReadBit(); + std::string playerName = recvPacket.ReadString(nameLength); + if (Guild* guild = GetPlayer()->GetGuild()) + guild->HandleSetNewGuildMaster(this, playerName); +} diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 60966ace011..97a535cd38b 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -27,6 +27,8 @@ #include "UpdateData.h" #include "ObjectAccessor.h" #include "SpellInfo.h" +#include "DB2Stores.h" +#include <vector> void WorldSession::HandleSplitItemOpcode(WorldPacket& recvData) { @@ -54,7 +56,7 @@ void WorldSession::HandleSplitItemOpcode(WorldPacket& recvData) if (!_player->IsValidPos(dstbag, dstslot, false)) // can be autostore pos { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + _player->SendEquipError(EQUIP_ERR_WRONG_SLOT, NULL, NULL); return; } @@ -81,7 +83,7 @@ void WorldSession::HandleSwapInvItemOpcode(WorldPacket& recvData) if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, dstslot, true)) { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + _player->SendEquipError(EQUIP_ERR_WRONG_SLOT, NULL, NULL); return; } @@ -145,7 +147,7 @@ void WorldSession::HandleSwapItem(WorldPacket& recvData) if (!_player->IsValidPos(dstbag, dstslot, true)) { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + _player->SendEquipError(EQUIP_ERR_WRONG_SLOT, NULL, NULL); return; } @@ -260,7 +262,7 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPacket& recvData) void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData) { - //TC_LOG_DEBUG("network", "WORLD: CMSG_DESTROYITEM"); + //TC_LOG_DEBUG("network", "WORLD: CMSG_DESTROY_ITEM"); uint8 bag, slot, count, data1, data2, data3; recvData >> bag >> slot >> count >> data1 >> data2 >> data3; @@ -288,7 +290,7 @@ void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData) if (pItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_INDESTRUCTIBLE) { - _player->SendEquipError(EQUIP_ERR_CANT_DROP_SOULBOUND, NULL, NULL); + _player->SendEquipError(EQUIP_ERR_DROP_BOUND_ITEM, NULL, NULL); return; } @@ -301,174 +303,11 @@ void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData) _player->DestroyItem(bag, slot, true); } -// Only _static_ data send in this packet !!! -void WorldSession::HandleItemQuerySingleOpcode(WorldPacket& recvData) -{ - //TC_LOG_DEBUG("network", "WORLD: CMSG_ITEM_QUERY_SINGLE"); - uint32 item; - recvData >> item; - - TC_LOG_INFO("network", "STORAGE: Item Query = %u", item); - - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item); - if (pProto) - { - std::string Name = pProto->Name1; - std::string Description = pProto->Description; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - if (ItemLocale const* il = sObjectMgr->GetItemLocale(pProto->ItemId)) - { - ObjectMgr::GetLocaleString(il->Name, loc_idx, Name); - ObjectMgr::GetLocaleString(il->Description, loc_idx, Description); - } - } - // guess size - WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600); - data << pProto->ItemId; - data << pProto->Class; - data << pProto->SubClass; - data << pProto->SoundOverrideSubclass; - data << Name; - data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name... - data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00); - data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00); - data << pProto->DisplayInfoID; - data << pProto->Quality; - data << pProto->Flags; - data << pProto->Flags2; - data << pProto->BuyPrice; - data << pProto->SellPrice; - data << pProto->InventoryType; - data << pProto->AllowableClass; - data << pProto->AllowableRace; - data << pProto->ItemLevel; - data << pProto->RequiredLevel; - data << pProto->RequiredSkill; - data << pProto->RequiredSkillRank; - data << pProto->RequiredSpell; - data << pProto->RequiredHonorRank; - data << pProto->RequiredCityRank; - data << pProto->RequiredReputationFaction; - data << pProto->RequiredReputationRank; - data << int32(pProto->MaxCount); - data << int32(pProto->Stackable); - data << pProto->ContainerSlots; - data << pProto->StatsCount; // item stats count - for (uint32 i = 0; i < pProto->StatsCount; ++i) - { - data << pProto->ItemStat[i].ItemStatType; - data << pProto->ItemStat[i].ItemStatValue; - } - data << pProto->ScalingStatDistribution; // scaling stats distribution - data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column - for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) - { - data << pProto->Damage[i].DamageMin; - data << pProto->Damage[i].DamageMax; - data << pProto->Damage[i].DamageType; - } - - // resistances (7) - data << pProto->Armor; - data << pProto->HolyRes; - data << pProto->FireRes; - data << pProto->NatureRes; - data << pProto->FrostRes; - data << pProto->ShadowRes; - data << pProto->ArcaneRes; - - data << pProto->Delay; - data << pProto->AmmoType; - data << pProto->RangedModRange; - - for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s) - { - // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown - // use `item_template` or if not set then only use spell cooldowns - SpellInfo const* spell = sSpellMgr->GetSpellInfo(pProto->Spells[s].SpellId); - if (spell) - { - bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0; - - data << pProto->Spells[s].SpellId; - data << pProto->Spells[s].SpellTrigger; - data << uint32(-abs(pProto->Spells[s].SpellCharges)); - - if (db_data) - { - data << uint32(pProto->Spells[s].SpellCooldown); - data << uint32(pProto->Spells[s].SpellCategory); - data << uint32(pProto->Spells[s].SpellCategoryCooldown); - } - else - { - data << uint32(spell->RecoveryTime); - data << uint32(spell->GetCategory()); - data << uint32(spell->CategoryRecoveryTime); - } - } - else - { - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(-1); - data << uint32(0); - data << uint32(-1); - } - } - data << pProto->Bonding; - data << Description; - data << pProto->PageText; - data << pProto->LanguageID; - data << pProto->PageMaterial; - data << pProto->StartQuest; - data << pProto->LockID; - data << int32(pProto->Material); - data << pProto->Sheath; - data << pProto->RandomProperty; - data << pProto->RandomSuffix; - data << pProto->Block; - data << pProto->ItemSet; - data << pProto->MaxDurability; - data << pProto->Area; - data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch - data << pProto->BagFamily; - data << pProto->TotemCategory; - for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s) - { - data << pProto->Socket[s].Color; - data << pProto->Socket[s].Content; - } - data << pProto->socketBonus; - data << pProto->GemProperties; - data << pProto->RequiredDisenchantSkill; - data << pProto->ArmorDamageModifier; - data << pProto->Duration; // added in 2.4.2.8209, duration (seconds) - data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory - data << pProto->HolidayId; // Holiday.dbc? - SendPacket(&data); - } - else - { - TC_LOG_DEBUG("network", "WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item); - WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4); - data << uint32(item | 0x80000000); - SendPacket(&data); - } -} - void WorldSession::HandleReadItem(WorldPacket& recvData) { - //TC_LOG_DEBUG("network", "WORLD: CMSG_READ_ITEM"); - uint8 bag, slot; recvData >> bag >> slot; - //TC_LOG_INFO("network", "STORAGE: Read bag = %u, slot = %u", bag, slot); Item* pItem = _player->GetItemByPos(bag, slot); if (pItem && pItem->GetTemplate()->PageText) @@ -478,7 +317,7 @@ void WorldSession::HandleReadItem(WorldPacket& recvData) InventoryResult msg = _player->CanUseItem(pItem); if (msg == EQUIP_ERR_OK) { - data.Initialize (SMSG_READ_ITEM_OK, 8); + data.Initialize(SMSG_READ_ITEM_OK, 8); TC_LOG_INFO("network", "STORAGE: Item page sent"); } else @@ -509,7 +348,7 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData) if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid); return; } @@ -523,21 +362,21 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData) // prevent sell not owner item if (_player->GetGUID() != pItem->GetOwnerGUID()) { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid); return; } // prevent sell non empty bag by drag-and-drop at vendor's item list if (pItem->IsNotEmptyBag()) { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid); return; } // prevent sell currently looted item if (_player->GetLootGUID() == pItem->GetGUID()) { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid); return; } @@ -555,7 +394,7 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData) // prevent sell more items that exist in stack (possible only not from client) if (count > pItem->GetCount()) { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid); return; } } @@ -571,7 +410,7 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData) if (!pNewItem) { TC_LOG_ERROR("network", "WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count); - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid); return; } @@ -598,11 +437,11 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData) _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); } else - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid); return; } } - _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, creature, itemguid, 0); + _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, creature, itemguid); return; } @@ -618,7 +457,7 @@ void WorldSession::HandleBuybackItem(WorldPacket& recvData) if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0); return; } @@ -630,7 +469,7 @@ void WorldSession::HandleBuybackItem(WorldPacket& recvData) if (pItem) { uint32 price = _player->GetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START); - if (!_player->HasEnoughMoney(price)) + if (!_player->HasEnoughMoney(uint64(price))) { _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, pItem->GetEntry(), 0); return; @@ -670,24 +509,15 @@ void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recvData) return; // cheating uint8 bag = NULL_BAG; // init for case invalid bagGUID - + Item* bagItem = NULL; // find bag slot by bag guid if (bagguid == _player->GetGUID()) bag = INVENTORY_SLOT_BAG_0; else - { - for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) - { - if (Bag* pBag = _player->GetBagByPos(i)) - { - if (bagguid == pBag->GetGUID()) - { - bag = i; - break; - } - } - } - } + bagItem = _player->GetItemByGuid(bagguid); + + if (bagItem && bagItem->IsBag()) + bag = bagItem->GetSlot(); // bag not found, cheating? if (bag == NULL_BAG) @@ -699,11 +529,12 @@ void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recvData) void WorldSession::HandleBuyItemOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_BUY_ITEM"); - uint64 vendorguid; + uint64 vendorguid, bagGuid; uint32 item, slot, count; - uint8 unk1; + uint8 itemType; // 1 = item, 2 = currency + uint8 bagSlot; - recvData >> vendorguid >> item >> slot >> count >> unk1; + recvData >> vendorguid >> itemType >> item >> slot >> count >> bagGuid >> bagSlot; // client expects count starting at 1, and we send vendorslot+1 to client already if (slot > 0) @@ -711,7 +542,22 @@ void WorldSession::HandleBuyItemOpcode(WorldPacket& recvData) else return; // cheating - GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, NULL_BAG, NULL_SLOT); + if (itemType == ITEM_VENDOR_TYPE_ITEM) + { + Item* bagItem = _player->GetItemByGuid(bagGuid); + + uint8 bag = NULL_BAG; + if (bagItem && bagItem->IsBag()) + bag = bagItem->GetSlot(); + else if (bagGuid == GetPlayer()->GetGUID()) // The client sends the player guid when trying to store an item in the default backpack + bag = INVENTORY_SLOT_BAG_0; + + GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, bag, bagSlot); + } + else if (itemType == ITEM_VENDOR_TYPE_CURRENCY) + GetPlayer()->BuyCurrencyFromVendorSlot(vendorguid, slot, item, count); + else + TC_LOG_DEBUG("network", "WORLD: received wrong itemType (%u) in HandleBuyItemOpcode", itemType); } void WorldSession::HandleListInventoryOpcode(WorldPacket& recvData) @@ -736,7 +582,7 @@ void WorldSession::SendListInventory(uint64 vendorGuid) if (!vendor) { TC_LOG_DEBUG("network", "WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorGuid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0); return; } @@ -748,79 +594,155 @@ void WorldSession::SendListInventory(uint64 vendorGuid) if (vendor->HasUnitState(UNIT_STATE_MOVING)) vendor->StopMoving(); - VendorItemData const* items = vendor->GetVendorItems(); - if (!items) - { - WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + 1); - data << uint64(vendorGuid); - data << uint8(0); // count == 0, next will be error code - data << uint8(0); // "Vendor has no inventory" - SendPacket(&data); - return; - } - - uint8 itemCount = items->GetItemCount(); - uint8 count = 0; + VendorItemData const* vendorItems = vendor->GetVendorItems(); + uint32 rawItemCount = vendorItems ? vendorItems->GetItemCount() : 0; - WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + itemCount * 8 * 4); - data << uint64(vendorGuid); + //if (rawItemCount > 300), + // rawItemCount = 300; // client cap but uint8 max value is 255 - size_t countPos = data.wpos(); - data << uint8(count); + ByteBuffer itemsData(32 * rawItemCount); + std::vector<bool> enablers; + enablers.reserve(2 * rawItemCount); - float discountMod = _player->GetReputationPriceDiscount(vendor); - - for (uint8 slot = 0; slot < itemCount; ++slot) + const float discountMod = _player->GetReputationPriceDiscount(vendor); + uint8 count = 0; + for (uint32 slot = 0; slot < rawItemCount; ++slot) { - if (VendorItem const* item = items->GetItem(slot)) + VendorItem const* vendorItem = vendorItems->GetItem(slot); + if (!vendorItem) + continue; + + if (vendorItem->Type == ITEM_VENDOR_TYPE_ITEM) { - if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item->item)) + ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(vendorItem->item); + if (!itemTemplate) + continue; + + uint32 leftInStock = !vendorItem->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(vendorItem); + if (!_player->IsGameMaster()) // ignore conditions if GM on { - if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_WHEN_PICKED_UP && !_player->IsGameMaster()) + // Respect allowed class + if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_WHEN_PICKED_UP) continue; - // Only display items in vendor lists for the team the - // player is on. If GM on, display all items. - if (!_player->IsGameMaster() && ((itemTemplate->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || (itemTemplate->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE))) + + // Only display items in vendor lists for the team the player is on + if ((itemTemplate->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || + (itemTemplate->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE)) continue; // Items sold out are not displayed in list - uint32 leftInStock = !item->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(item); - if (!_player->IsGameMaster() && !leftInStock) + if (leftInStock == 0) continue; + } - ConditionList conditions = sConditionMgr->GetConditionsForNpcVendorEvent(vendor->GetEntry(), item->item); - if (!sConditionMgr->IsObjectMeetToConditions(_player, vendor, conditions)) - { - TC_LOG_DEBUG("condition", "SendListInventory: conditions not met for creature entry %u item %u", vendor->GetEntry(), item->item); - continue; - } + ConditionList conditions = sConditionMgr->GetConditionsForNpcVendorEvent(vendor->GetEntry(), vendorItem->item); + if (!sConditionMgr->IsObjectMeetToConditions(_player, vendor, conditions)) + { + TC_LOG_DEBUG("condition", "SendListInventory: conditions not met for creature entry %u item %u", vendor->GetEntry(), vendorItem->item); + continue; + } - // reputation discount - int32 price = item->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0; + int32 price = vendorItem->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0; - data << uint32(slot + 1); // client expects counting to start at 1 - data << uint32(item->item); - data << uint32(itemTemplate->DisplayInfoID); - data << int32(leftInStock); - data << uint32(price); - data << uint32(itemTemplate->MaxDurability); - data << uint32(itemTemplate->BuyCount); - data << uint32(item->ExtendedCost); + if (int32 priceMod = _player->GetTotalAuraModifier(SPELL_AURA_MOD_VENDOR_ITEMS_PRICES)) + price -= CalculatePct(price, priceMod); - if (++count >= MAX_VENDOR_ITEMS) - break; + itemsData << uint32(slot + 1); // client expects counting to start at 1 + itemsData << uint32(itemTemplate->MaxDurability); + + if (vendorItem->ExtendedCost) + { + enablers.push_back(0); + itemsData << uint32(vendorItem->ExtendedCost); } + else + enablers.push_back(1); + + enablers.push_back(1); // item is unlocked + + itemsData << uint32(vendorItem->item); + itemsData << uint32(vendorItem->Type); // 1 is items, 2 is currency + itemsData << uint32(price); + itemsData << uint32(itemTemplate->DisplayInfoID); + // if (!unk "enabler") data << uint32(something); + itemsData << int32(leftInStock); + itemsData << uint32(itemTemplate->BuyCount); + + if (++count >= MAX_VENDOR_ITEMS) + break; } - } + else if (vendorItem->Type == ITEM_VENDOR_TYPE_CURRENCY) + { + CurrencyTypesEntry const* currencyTemplate = sCurrencyTypesStore.LookupEntry(vendorItem->item); + if (!currencyTemplate) + continue; - if (count == 0) - { - data << uint8(0); - SendPacket(&data); - return; + if (!vendorItem->ExtendedCost) + continue; // there's no price defined for currencies, only extendedcost is used + + itemsData << uint32(slot + 1); // client expects counting to start at 1 + itemsData << uint32(0); // max durability + + enablers.push_back(0); + itemsData << uint32(vendorItem->ExtendedCost); + + enablers.push_back(1); // item is unlocked + + itemsData << uint32(vendorItem->item); + itemsData << uint32(vendorItem->Type); // 1 is items, 2 is currency + itemsData << uint32(0); // price, only seen currency types that have Extended cost + itemsData << uint32(0); // displayId + // if (!unk "enabler") data << uint32(something); + itemsData << int32(-1); + itemsData << uint32(vendorItem->maxcount); + + if (++count >= MAX_VENDOR_ITEMS) + break; + } + // else error } - data.put<uint8>(countPos, count); + ObjectGuid guid = vendorGuid; + + WorldPacket data(SMSG_LIST_INVENTORY, 12 + itemsData.size()); + + data.WriteBit(guid[1]); + data.WriteBit(guid[0]); + + data.WriteBits(count, 21); // item count + + data.WriteBit(guid[3]); + data.WriteBit(guid[6]); + data.WriteBit(guid[5]); + data.WriteBit(guid[2]); + data.WriteBit(guid[7]); + + for (std::vector<bool>::const_iterator itr = enablers.begin(); itr != enablers.end(); ++itr) + data.WriteBit(*itr); + + data.WriteBit(guid[4]); + + data.FlushBits(); + data.append(itemsData); + + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[6]); + + // It doesn't matter what value is used here (PROBABLY its full vendor size) + // What matters is that if count of items we can see is 0 and this field is 1 + // then client will open the vendor list, otherwise it won't + if (rawItemCount) + data << uint8(rawItemCount); + else + data << uint8(vendor->IsArmorer()); + + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[7]); + SendPacket(&data); } @@ -838,7 +760,7 @@ void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket& recvData) if (!_player->IsValidPos(dstbag, NULL_SLOT, false)) // can be autostore pos { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + _player->SendEquipError(EQUIP_ERR_WRONG_SLOT, NULL, NULL); return; } @@ -867,7 +789,7 @@ void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket& recvData) if (dest.size() == 1 && dest[0].pos == src) { // just remove grey item state - _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + _player->SendEquipError(EQUIP_ERR_INTERNAL_BAG_ERROR, pItem, NULL); return; } @@ -882,8 +804,11 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) uint64 guid; recvPacket >> guid; + WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4); if (!CanUseBank(guid)) { + data << uint32(ERR_BANKSLOT_NOTBANKER); + SendPacket(&data); TC_LOG_DEBUG("network", "WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); return; } @@ -897,8 +822,6 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot); - WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4); - if (!slotEntry) { data << uint32(ERR_BANKSLOT_FAILED_TOO_MANY); @@ -908,7 +831,7 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) uint32 price = slotEntry->price; - if (!_player->HasEnoughMoney(price)) + if (!_player->HasEnoughMoney(uint64(price))) { data << uint32(ERR_BANKSLOT_INSUFFICIENT_FUNDS); SendPacket(&data); @@ -916,7 +839,7 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) } _player->SetBankBagSlotCount(slot); - _player->ModifyMoney(-int32(price)); + _player->ModifyMoney(-int64(price)); data << uint32(ERR_BANKSLOT_OK); SendPacket(&data); @@ -952,7 +875,7 @@ void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket) if (dest.size() == 1 && dest[0].pos == pItem->GetPos()) { - _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + _player->SendEquipError(EQUIP_ERR_CANT_SWAP, pItem, NULL); return; } @@ -1008,36 +931,9 @@ void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) } } -void WorldSession::HandleSetAmmoOpcode(WorldPacket& recvData) -{ - if (!_player->IsAlive()) - { - _player->SendEquipError(EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL); - return; - } - - TC_LOG_DEBUG("network", "WORLD: CMSG_SET_AMMO"); - uint32 item; - - recvData >> item; - - if (item) - { - if (!_player->GetItemCount(item)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - _player->SetAmmo(item); - } - else - _player->RemoveAmmo(); -} - void WorldSession::SendEnchantmentLog(uint64 target, uint64 caster, uint32 itemId, uint32 enchantId) { - WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4)); // last check 2.0.10 + WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4)); data.appendPackGUID(target); data.appendPackGUID(caster); data << uint32(itemId); @@ -1056,30 +952,6 @@ void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid, SendPacket(&data); } -void WorldSession::HandleItemNameQueryOpcode(WorldPacket& recvData) -{ - uint32 itemid; - recvData >> itemid; - recvData.read_skip<uint64>(); // guid - - TC_LOG_DEBUG("network", "WORLD: CMSG_ITEM_NAME_QUERY %u", itemid); - ItemSetNameEntry const* pName = sObjectMgr->GetItemSetNameEntry(itemid); - if (pName) - { - std::string Name = pName->name; - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - if (ItemSetNameLocale const* isnl = sObjectMgr->GetItemSetNameLocale(itemid)) - ObjectMgr::GetLocaleString(isnl->Name, loc_idx, Name); - - WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+Name.size()+1+4)); - data << uint32(itemid); - data << Name; - data << uint32(pName->InventoryType); - SendPacket(&data); - } -} - void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_WRAP_ITEM"); @@ -1114,44 +986,44 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData) if (item == gift) // not possable with pacjket from real client { - _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); + _player->SendEquipError(EQUIP_ERR_CANT_WRAP_WRAPPED, item, NULL); return; } if (item->IsEquipped()) { - _player->SendEquipError(EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL); + _player->SendEquipError(EQUIP_ERR_CANT_WRAP_EQUIPPED, item, NULL); return; } if (item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); { - _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); + _player->SendEquipError(EQUIP_ERR_CANT_WRAP_WRAPPED, item, NULL); return; } if (item->IsBag()) { - _player->SendEquipError(EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL); + _player->SendEquipError(EQUIP_ERR_CANT_WRAP_BAGS, item, NULL); return; } if (item->IsSoulBound()) { - _player->SendEquipError(EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL); + _player->SendEquipError(EQUIP_ERR_CANT_WRAP_BOUND, item, NULL); return; } if (item->GetMaxStackCount() != 1) { - _player->SendEquipError(EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL); + _player->SendEquipError(EQUIP_ERR_CANT_WRAP_STACKABLE, item, NULL); return; } // maybe not correct check (it is better than nothing) - if (item->GetTemplate()->MaxCount>0) + if (item->GetTemplate()->MaxCount > 0) { - _player->SendEquipError(EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL); + _player->SendEquipError(EQUIP_ERR_CANT_WRAP_UNIQUE, item, NULL); return; } @@ -1257,6 +1129,14 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData) // tried to put meta gem in normal socket if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) return; + + // tried to put normal gem in cogwheel socket + if (itemProto->Socket[i].Color == SOCKET_COLOR_COGWHEEL && GemProps[i]->color != SOCKET_COLOR_COGWHEEL) + return; + + // tried to put cogwheel gem in normal socket + if (itemProto->Socket[i].Color != SOCKET_COLOR_COGWHEEL && GemProps[i]->color == SOCKET_COLOR_COGWHEEL) + return; } uint32 GemEnchants[MAX_GEM_SOCKETS]; @@ -1365,7 +1245,10 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData) { itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i], 0, 0, _player->GetGUID()); if (Item* guidItem = _player->GetItemByGuid(gem_guids[i])) - _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); + { + uint32 gemCount = 1; + _player->DestroyItemCount(guidItem, gemCount, true); + } } } @@ -1393,15 +1276,15 @@ void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT"); - uint32 eslot; + uint32 slot; - recvData >> eslot; + recvData >> slot; // apply only to equipped item - if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, eslot)) + if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, slot)) return; - Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot); + Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (!item) return; @@ -1462,7 +1345,7 @@ void WorldSession::HandleItemTextQuery(WorldPacket& recvData ) TC_LOG_DEBUG("network", "CMSG_ITEM_TEXT_QUERY item guid: %u", GUID_LOPART(itemGuid)); - WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, (4+10)); // guess size + WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, 14); // guess size if (Item* item = _player->GetItemByGuid(itemGuid)) { @@ -1478,6 +1361,289 @@ void WorldSession::HandleItemTextQuery(WorldPacket& recvData ) SendPacket(&data); } +void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_TRANSMOGRIFY_ITEMS"); + Player* player = GetPlayer(); + + // Read data + uint32 count = recvData.ReadBits(22); + + if (count >= EQUIPMENT_SLOT_END) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) sent a wrong count (%u) when transmogrifying items.", player->GetGUIDLow(), player->GetName().c_str(), count); + recvData.rfinish(); + return; + } + + std::vector<ObjectGuid> itemGuids(count, ObjectGuid(0)); + std::vector<uint32> newEntries(count, 0); + std::vector<uint32> slots(count, 0); + + for (uint8 i = 0; i < count; ++i) + { + itemGuids[i][0] = recvData.ReadBit(); + itemGuids[i][5] = recvData.ReadBit(); + itemGuids[i][6] = recvData.ReadBit(); + itemGuids[i][2] = recvData.ReadBit(); + itemGuids[i][3] = recvData.ReadBit(); + itemGuids[i][7] = recvData.ReadBit(); + itemGuids[i][4] = recvData.ReadBit(); + itemGuids[i][1] = recvData.ReadBit(); + } + + ObjectGuid npcGuid; + npcGuid[7] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + npcGuid[1] = recvData.ReadBit(); + npcGuid[4] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + npcGuid[2] = recvData.ReadBit(); + + recvData.FlushBits(); + + for (uint32 i = 0; i < count; ++i) + { + recvData >> newEntries[i]; + + recvData.ReadByteSeq(itemGuids[i][1]); + recvData.ReadByteSeq(itemGuids[i][5]); + recvData.ReadByteSeq(itemGuids[i][0]); + recvData.ReadByteSeq(itemGuids[i][4]); + recvData.ReadByteSeq(itemGuids[i][6]); + recvData.ReadByteSeq(itemGuids[i][7]); + recvData.ReadByteSeq(itemGuids[i][3]); + recvData.ReadByteSeq(itemGuids[i][2]); + + recvData >> slots[i]; + } + + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[2]); + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(npcGuid[4]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(npcGuid[6]); + recvData.ReadByteSeq(npcGuid[0]); + + // Validate + + if (!player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_TRANSMOGRIFIER)) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + int32 cost = 0; + for (uint8 i = 0; i < count; ++i) + { + // slot of the transmogrified item + if (slots[i] >= EQUIPMENT_SLOT_END) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an item (lowguid: %u) with a wrong slot (%u) when transmogrifying items.", player->GetGUIDLow(), player->GetName().c_str(), GUID_LOPART(itemGuids[i]), slots[i]); + return; + } + + // entry of the transmogrifier item, if it's not 0 + if (newEntries[i]) + { + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newEntries[i]); + if (!proto) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify to an invalid item (entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), newEntries[i]); + return; + } + } + + Item* itemTransmogrifier = NULL; + // guid of the transmogrifier item, if it's not 0 + if (itemGuids[i]) + { + itemTransmogrifier = player->GetItemByGuid(itemGuids[i]); + if (!itemTransmogrifier) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify with an invalid item (lowguid: %u).", player->GetGUIDLow(), player->GetName().c_str(), GUID_LOPART(itemGuids[i])); + return; + } + } + + // transmogrified item + Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slots[i]); + if (!itemTransmogrified) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUIDLow(), player->GetName().c_str(), slots[i]); + return; + } + + // uint16 tempDest; + //// has to be able to equip item transmogrified item + //if (!player->CanEquipItem(slots[i], tempDest, itemTransmogrified, true, true)) + //{ + // TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) can't equip the item to be transmogrified (slot: %u, entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), slots[i], itemTransmogrified->GetEntry()); + // return; + //} + // + //// has to be able to equip item transmogrifier item + //if (!player->CanEquipItem(slots[i], tempDest, itemTransmogrifier, true, true)) + //{ + // TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) can't equip the transmogrifier item (slot: %u, entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), slots[i], itemTransmogrifier->GetEntry()); + // return; + //} + + if (!newEntries[i]) // reset look + { + itemTransmogrified->ClearEnchantment(TRANSMOGRIFY_ENCHANTMENT_SLOT); + player->SetVisibleItemSlot(slots[i], itemTransmogrified); + } + else + { + if (itemTransmogrifier->GetEntry() != newEntries[i]) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify with an invalid entry (entry: %u) for item (lowguid: %u).", player->GetGUIDLow(), player->GetName().c_str(), newEntries[i], GUID_LOPART(itemGuids[i])); + return; + } + + if (!Item::CanTransmogrifyItemWithItem(itemTransmogrified, itemTransmogrifier)) + { + TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUIDLow(), player->GetName().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry()); + return; + } + + // All okay, proceed + itemTransmogrified->SetEnchantment(TRANSMOGRIFY_ENCHANTMENT_SLOT, newEntries[i], 0, 0); + player->SetVisibleItemSlot(slots[i], itemTransmogrified); + + itemTransmogrified->UpdatePlayedTime(player); + + itemTransmogrified->SetOwnerGUID(player->GetGUID()); + itemTransmogrified->SetNotRefundable(player); + itemTransmogrified->ClearSoulboundTradeable(player); + + if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE) + itemTransmogrifier->SetBinding(true); + + itemTransmogrifier->SetOwnerGUID(player->GetGUID()); + itemTransmogrifier->SetNotRefundable(player); + itemTransmogrifier->ClearSoulboundTradeable(player); + + cost += itemTransmogrified->GetSpecialPrice(); + } + } + + // trusting the client, if it got here it has to have enough money + // ... unless client was modified + if (cost) // 0 cost if reverting look + player->ModifyMoney(-cost); +} + +void WorldSession::SendReforgeResult(bool success) +{ + WorldPacket data(SMSG_REFORGE_RESULT, 1); + data.WriteBit(success); + data.FlushBits(); + SendPacket(&data); +} + +void WorldSession::HandleReforgeItemOpcode(WorldPacket& recvData) +{ + uint32 slot, reforgeEntry; + ObjectGuid guid; + uint32 bag; + Player* player = GetPlayer(); + + recvData >> reforgeEntry >> slot >> bag; + + guid[2] = recvData.ReadBit(); + guid[6] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + guid[4] = recvData.ReadBit(); + guid[1] = recvData.ReadBit(); + guid[0] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + guid[5] = recvData.ReadBit(); + + recvData.ReadByteSeq(guid[2]); + recvData.ReadByteSeq(guid[3]); + recvData.ReadByteSeq(guid[6]); + recvData.ReadByteSeq(guid[4]); + recvData.ReadByteSeq(guid[1]); + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[5]); + + if (!player->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_REFORGER)) + { + TC_LOG_DEBUG("network", "WORLD: HandleReforgeItemOpcode - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(guid)); + SendReforgeResult(false); + return; + } + + Item* item = player->GetItemByPos(bag, slot); + + if (!item) + { + TC_LOG_DEBUG("network", "WORLD: HandleReforgeItemOpcode - Player (Guid: %u Name: %s) tried to reforge an invalid/non-existant item.", player->GetGUIDLow(), player->GetName().c_str()); + SendReforgeResult(false); + return; + } + + if (!reforgeEntry) + { + if (!item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)) + { + TC_LOG_ERROR("network", "WORLD: HandleReforgeItemOpcode - Player (Guid: %u Name: %s) tried to remove reforge from non-reforged item (Entry: %u)", player->GetGUIDLow(), player->GetName().c_str(), item->GetEntry()); + SendReforgeResult(false); + return; + } + + // Reset the item + if (item->IsEquipped()) + player->ApplyReforgeEnchantment(item, false); + item->ClearEnchantment(REFORGE_ENCHANTMENT_SLOT); + SendReforgeResult(true); + return; + } + + if (item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)) + { + TC_LOG_ERROR("network", "WORLD: HandleReforgeItemOpcode - Player (Guid: %u Name: %s) tried to reforge an already reforged item (Entry: %u)", player->GetGUIDLow(), player->GetName().c_str(), item->GetEntry()); + SendReforgeResult(false); + return; + } + + ItemReforgeEntry const* stats = sItemReforgeStore.LookupEntry(reforgeEntry); + if (!stats) + { + TC_LOG_DEBUG("network", "WORLD: HandleReforgeItemOpcode - Player (Guid: %u Name: %s) tried to reforge an item with invalid reforge entry (%u).", player->GetGUIDLow(), player->GetName().c_str(), reforgeEntry); + SendReforgeResult(false); + return; + } + + if (!item->GetReforgableStat(ItemModType(stats->SourceStat)) || item->GetReforgableStat(ItemModType(stats->FinalStat))) // Cheating, you cant reforge to a stat that the item already has, nor reforge from a stat that the item does not have + { + SendReforgeResult(false); + return; + } + + if (!player->HasEnoughMoney(uint64(item->GetSpecialPrice()))) // cheating + { + SendReforgeResult(false); + return; + } + + player->ModifyMoney(-int64(item->GetSpecialPrice())); + + item->SetEnchantment(REFORGE_ENCHANTMENT_SLOT, reforgeEntry, 0, 0); + + SendReforgeResult(true); + + if (item->IsEquipped()) + player->ApplyReforgeEnchantment(item, true); +} + bool WorldSession::CanUseBank(uint64 bankerGUID) const { // bankerGUID parameter is optional, set to 0 by default. @@ -1494,4 +1660,4 @@ bool WorldSession::CanUseBank(uint64 bankerGUID) const } return true; -}
\ No newline at end of file +} diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index a984c033872..c67d0bbf895 100644 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -28,8 +28,13 @@ void BuildPlayerLockDungeonBlock(WorldPacket& data, lfg::LfgLockMap const& lock) data << uint32(lock.size()); // Size of lock dungeons for (lfg::LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it) { - data << uint32(it->first); // Dungeon entry (id + type) - data << uint32(it->second); // Lock status + TC_LOG_TRACE("lfg", "BuildPlayerLockDungeonBlock:: DungeonID: %u Lock status: %u Required itemLevel: %u Current itemLevel: %f", + (it->first & 0x00FFFFFF), it->second.lockStatus, it->second.requiredItemLevel, it->second.currentItemLevel); + + data << uint32(it->first); // Dungeon entry (id + type) + data << uint32(it->second.lockStatus); // Lock status + data << uint32(it->second.requiredItemLevel); // Required itemLevel + data << uint32(it->second.currentItemLevel); // Current itemLevel } } @@ -43,6 +48,40 @@ void BuildPartyLockDungeonBlock(WorldPacket& data, lfg::LfgLockPartyMap const& l } } +void BuildQuestReward(WorldPacket& data, Quest const* quest, Player* player) +{ + uint8 rewCount = quest->GetRewItemsCount() + quest->GetRewCurrencyCount(); + + data << uint32(quest->GetRewOrReqMoney()); + data << uint32(quest->XPValue(player)); + data << uint8(rewCount); + if (rewCount) + { + for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) + { + if (uint32 currencyId = quest->RewardCurrencyId[i]) + { + data << uint32(currencyId); + data << uint32(0); + data << uint32(quest->RewardCurrencyCount[i]); + data << uint8(1); // Is currency + } + } + + for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) + { + if (uint32 itemId = quest->RewardItemId[i]) + { + ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId); + data << uint32(itemId); + data << uint32(item ? item->DisplayInfoID : 0); + data << uint32(quest->RewardItemIdCount[i]); + data << uint8(0); // Is currency + } + } + } +} + void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) { if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER) || @@ -53,12 +92,15 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) return; } - uint8 numDungeons; uint32 roles; recvData >> roles; - recvData.read_skip<uint16>(); // uint8 (always 0) - uint8 (always 0) - recvData >> numDungeons; + for (int32 i = 0; i < 3; ++i) + recvData.read_skip<uint32>(); + + uint32 commentLen = recvData.ReadBits(9); + uint32 numDungeons = recvData.ReadBits(24); + if (!numDungeons) { TC_LOG_DEBUG("lfg", "CMSG_LFG_JOIN %s no dungeons selected", GetPlayerInfo().c_str()); @@ -66,48 +108,113 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) return; } + std::string comment = recvData.ReadString(commentLen); + lfg::LfgDungeonSet newDungeons; - for (int8 i = 0; i < numDungeons; ++i) + for (uint32 i = 0; i < numDungeons; ++i) { uint32 dungeon; recvData >> dungeon; newDungeons.insert((dungeon & 0x00FFFFFF)); // remove the type from the dungeon entry } - recvData.read_skip<uint32>(); // for 0..uint8 (always 3) { uint8 (always 0) } - - std::string comment; - recvData >> comment; TC_LOG_DEBUG("lfg", "CMSG_LFG_JOIN %s roles: %u, Dungeons: %u, Comment: %s", GetPlayerInfo().c_str(), roles, uint8(newDungeons.size()), comment.c_str()); sLFGMgr->JoinLfg(GetPlayer(), uint8(roles), newDungeons, comment); } -void WorldSession::HandleLfgLeaveOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleLfgLeaveOpcode(WorldPacket& recvData) { + ObjectGuid leaveGuid; Group* group = GetPlayer()->GetGroup(); uint64 guid = GetPlayer()->GetGUID(); uint64 gguid = group ? group->GetGUID() : guid; - TC_LOG_DEBUG("lfg", "CMSG_LFG_LEAVE %s in group: %u", - GetPlayerInfo().c_str(), group ? 1 : 0); + recvData.read_skip<uint32>(); // Always 8 + recvData.read_skip<uint32>(); // Join date + recvData.read_skip<uint32>(); // Always 3 + recvData.read_skip<uint32>(); // Queue Id + + leaveGuid[4] = recvData.ReadBit(); + leaveGuid[5] = recvData.ReadBit(); + leaveGuid[0] = recvData.ReadBit(); + leaveGuid[6] = recvData.ReadBit(); + leaveGuid[2] = recvData.ReadBit(); + leaveGuid[7] = recvData.ReadBit(); + leaveGuid[1] = recvData.ReadBit(); + leaveGuid[3] = recvData.ReadBit(); + + recvData.ReadByteSeq(leaveGuid[7]); + recvData.ReadByteSeq(leaveGuid[4]); + recvData.ReadByteSeq(leaveGuid[3]); + recvData.ReadByteSeq(leaveGuid[2]); + recvData.ReadByteSeq(leaveGuid[6]); + recvData.ReadByteSeq(leaveGuid[0]); + recvData.ReadByteSeq(leaveGuid[1]); + recvData.ReadByteSeq(leaveGuid[5]); + + TC_LOG_DEBUG("lfg", "CMSG_LFG_LEAVE %s in group: %u sent guid " UI64FMTD ".", + GetPlayerInfo().c_str(), group ? 1 : 0, uint64(leaveGuid)); // Check cheating - only leader can leave the queue - if (!group || group->GetLeaderGUID() == GetPlayer()->GetGUID()) + if (!group || group->GetLeaderGUID() == guid) sLFGMgr->LeaveLfg(gguid); } void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recvData) { - uint32 lfgGroupID; // Internal lfgGroupID - bool accept; // Accept to join? - recvData >> lfgGroupID; - recvData >> accept; + uint32 proposalID; // Proposal ID + bool accept; + + ObjectGuid guid1; + ObjectGuid guid2; + + recvData >> proposalID; + recvData.read_skip<uint32>(); + recvData.read_skip<uint32>(); + recvData.read_skip<uint32>(); + + guid2[4] = recvData.ReadBit(); + guid2[5] = recvData.ReadBit(); + guid2[0] = recvData.ReadBit(); + guid2[6] = recvData.ReadBit(); + guid2[2] = recvData.ReadBit(); + guid2[7] = recvData.ReadBit(); + guid2[1] = recvData.ReadBit(); + guid2[3] = recvData.ReadBit(); + + recvData.ReadByteSeq(guid2[7]); + recvData.ReadByteSeq(guid2[4]); + recvData.ReadByteSeq(guid2[3]); + recvData.ReadByteSeq(guid2[2]); + recvData.ReadByteSeq(guid2[6]); + recvData.ReadByteSeq(guid2[0]); + recvData.ReadByteSeq(guid2[1]); + recvData.ReadByteSeq(guid2[5]); + + guid1[7] = recvData.ReadBit(); + accept = recvData.ReadBit(); + guid1[1] = recvData.ReadBit(); + guid1[3] = recvData.ReadBit(); + guid1[0] = recvData.ReadBit(); + guid1[5] = recvData.ReadBit(); + guid1[4] = recvData.ReadBit(); + guid1[6] = recvData.ReadBit(); + guid1[2] = recvData.ReadBit(); + + recvData.ReadByteSeq(guid1[7]); + recvData.ReadByteSeq(guid1[1]); + recvData.ReadByteSeq(guid1[5]); + recvData.ReadByteSeq(guid1[6]); + recvData.ReadByteSeq(guid1[3]); + recvData.ReadByteSeq(guid1[4]); + recvData.ReadByteSeq(guid1[0]); + recvData.ReadByteSeq(guid1[2]); TC_LOG_DEBUG("lfg", "CMSG_LFG_PROPOSAL_RESULT %s proposal: %u accept: %u", - GetPlayerInfo().c_str(), lfgGroupID, accept ? 1 : 0); - sLFGMgr->UpdateProposal(lfgGroupID, GetPlayer()->GetGUID(), accept); + GetPlayerInfo().c_str(), proposalID, accept ? 1 : 0); + sLFGMgr->UpdateProposal(proposalID, GetPlayer()->GetGUID(), accept); } void WorldSession::HandleLfgSetRolesOpcode(WorldPacket& recvData) @@ -160,11 +267,20 @@ void WorldSession::HandleLfgTeleportOpcode(WorldPacket& recvData) sLFGMgr->TeleportPlayer(GetPlayer(), out, true); } -void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleLfgGetLockInfoOpcode(WorldPacket& recvData) +{ + bool forPlayer = recvData.ReadBit(); + TC_LOG_DEBUG("lfg", "CMSG_LFG_LOCK_INFO_REQUEST %s for %s", GetPlayerInfo().c_str(), (forPlayer ? "player" : "party")); + + if (forPlayer) + SendLfgPlayerLockInfo(); + else + SendLfgPartyLockInfo(); +} + +void WorldSession::SendLfgPlayerLockInfo() { uint64 guid = GetPlayer()->GetGUID(); - TC_LOG_DEBUG("lfg", "CMSG_LFG_PLAYER_LOCK_INFO_REQUEST %s", - GetPlayerInfo().c_str()); // Get Random dungeons that can be done at a certain level and expansion uint8 level = GetPlayer()->getLevel(); @@ -197,45 +313,46 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData* } } - if (quest) + data << uint8(done); + data << uint32(0); // currencyQuantity + data << uint32(0); // some sort of overall cap/weekly cap + data << uint32(0); // currencyID + data << uint32(0); // tier1Quantity + data << uint32(0); // tier1Limit + data << uint32(0); // overallQuantity + data << uint32(0); // overallLimit + data << uint32(0); // periodPurseQuantity + data << uint32(0); // periodPurseLimit + data << uint32(0); // purseQuantity + data << uint32(0); // purseLimit + data << uint32(0); // some sort of reward for completion + data << uint32(0); // completedEncounters + data << uint8(0); // Call to Arms eligible + + for (uint32 i = 0; i < 3; ++i) { - data << uint8(done); - data << uint32(quest->GetRewOrReqMoney()); - data << uint32(quest->XPValue(GetPlayer())); - data << uint32(0); - data << uint32(0); - data << uint8(quest->GetRewItemsCount()); - if (quest->GetRewItemsCount()) - { - for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) - if (uint32 itemId = quest->RewardItemId[i]) - { - ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId); - data << uint32(itemId); - data << uint32(item ? item->DisplayInfoID : 0); - data << uint32(quest->RewardItemIdCount[i]); - } - } + data << uint32(0); // Call to Arms Role + //if (role) + // BuildQuestReward(data, ctaRoleQuest, GetPlayer()); } + + if (quest) + BuildQuestReward(data, quest, GetPlayer()); else { - data << uint8(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint8(0); + data << uint32(0); // Money + data << uint32(0); // XP + data << uint8(0); // Reward count } } + BuildPlayerLockDungeonBlock(data, lock); SendPacket(&data); } -void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData*/) +void WorldSession::SendLfgPartyLockInfo() { uint64 guid = GetPlayer()->GetGUID(); - TC_LOG_DEBUG("lfg", "CMSG_LFG_PARTY_LOCK_INFO_REQUEST %s", GetPlayerInfo().c_str()); - Group* group = GetPlayer()->GetGroup(); if (!group) return; @@ -257,7 +374,7 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData* uint32 size = 0; for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) - size += 8 + 4 + uint32(it->second.size()) * (4 + 4); + size += 8 + 4 + uint32(it->second.size()) * (4 + 4 + 4 + 4); TC_LOG_DEBUG("lfg", "SMSG_LFG_PARTY_INFO %s", GetPlayerInfo().c_str()); WorldPacket data(SMSG_LFG_PARTY_INFO, 1 + size); @@ -287,71 +404,45 @@ void WorldSession::HandleLfgGetStatus(WorldPacket& /*recvData*/) { TC_LOG_DEBUG("lfg", "CMSG_LFG_GET_STATUS %s", GetPlayerInfo().c_str()); + if (!GetPlayer()->isUsingLfg()) + return; + uint64 guid = GetPlayer()->GetGUID(); lfg::LfgUpdateData updateData = sLFGMgr->GetLfgStatus(guid); if (GetPlayer()->GetGroup()) { - SendLfgUpdateParty(updateData); + SendLfgUpdateStatus(updateData, true); updateData.dungeons.clear(); - SendLfgUpdatePlayer(updateData); + SendLfgUpdateStatus(updateData, false); } else { - SendLfgUpdatePlayer(updateData); + SendLfgUpdateStatus(updateData, false); updateData.dungeons.clear(); - SendLfgUpdateParty(updateData); + SendLfgUpdateStatus(updateData, true); } } -void WorldSession::SendLfgUpdatePlayer(lfg::LfgUpdateData const& updateData) -{ - bool queued = false; - uint8 size = uint8(updateData.dungeons.size()); - - switch (updateData.updateType) - { - case lfg::LFG_UPDATETYPE_JOIN_QUEUE: - case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE: - queued = true; - break; - case lfg::LFG_UPDATETYPE_UPDATE_STATUS: - queued = updateData.state == lfg::LFG_STATE_QUEUED; - break; - default: - break; - } - - TC_LOG_DEBUG("lfg", "SMSG_LFG_UPDATE_PLAYER %s updatetype: %u", - GetPlayerInfo().c_str(), updateData.updateType); - WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (size > 0 ? 1 : 0) * (1 + 1 + 1 + 1 + size * 4 + updateData.comment.length())); - data << uint8(updateData.updateType); // Lfg Update type - data << uint8(size > 0); // Extra info - if (size) - { - data << uint8(queued); // Join the queue - data << uint8(0); // unk - Always 0 - data << uint8(0); // unk - Always 0 - - data << uint8(size); - for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) - data << uint32(*it); - data << updateData.comment; - } - SendPacket(&data); -} - -void WorldSession::SendLfgUpdateParty(const lfg::LfgUpdateData& updateData) +void WorldSession::SendLfgUpdateStatus(lfg::LfgUpdateData const& updateData, bool party) { bool join = false; bool queued = false; uint8 size = uint8(updateData.dungeons.size()); + ObjectGuid guid = _player->GetGUID(); + time_t joinTime = sLFGMgr->GetQueueJoinTime(_player->GetGUID()); + uint32 queueId = sLFGMgr->GetQueueId(_player->GetGUID()); switch (updateData.updateType) { + case lfg::LFG_UPDATETYPE_JOIN_QUEUE_INITIAL: // Joined queue outside the dungeon + join = true; + break; + case lfg::LFG_UPDATETYPE_JOIN_QUEUE: case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE: // Rolecheck Success + join = true; queued = true; - // no break on purpose + break; case lfg::LFG_UPDATETYPE_PROPOSAL_BEGIN: join = true; break; @@ -363,25 +454,44 @@ void WorldSession::SendLfgUpdateParty(const lfg::LfgUpdateData& updateData) break; } - TC_LOG_DEBUG("lfg", "SMSG_LFG_UPDATE_PARTY %s updatetype: %u", - GetPlayerInfo().c_str(), updateData.updateType); - WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (size > 0 ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + size * 4 + updateData.comment.length())); + TC_LOG_DEBUG("lfg", "SMSG_LFG_UPDATE_STATUS %s updatetype: %u, party %s", + GetPlayerInfo().c_str(), updateData.updateType, party ? "true" : "false"); + + WorldPacket data(SMSG_LFG_UPDATE_STATUS, 1 + 8 + 3 + 2 + 1 + updateData.comment.length() + 4 + 4 + 1 + 1 + 1 + 4 + size); + data.WriteBit(guid[1]); + data.WriteBit(party); + data.WriteBits(size, 24); + data.WriteBit(guid[6]); + data.WriteBit(size > 0); // Extra info + data.WriteBits(updateData.comment.length(), 9); + data.WriteBit(guid[4]); + data.WriteBit(guid[7]); + data.WriteBit(guid[2]); + data.WriteBit(join); // LFG Join + data.WriteBit(guid[0]); + data.WriteBit(guid[3]); + data.WriteBit(guid[5]); + data.WriteBit(queued); // Join the queue + data << uint8(updateData.updateType); // Lfg Update type - data << uint8(size > 0); // Extra info - if (size) - { - data << uint8(join); // LFG Join - data << uint8(queued); // Join the queue + data.WriteString(updateData.comment); + data << uint32(queueId); // Queue Id + data << uint32(joinTime); // Join date + data.WriteByteSeq(guid[6]); + for (uint8 i = 0; i < 3; ++i) data << uint8(0); // unk - Always 0 - data << uint8(0); // unk - Always 0 - for (uint8 i = 0; i < 3; ++i) - data << uint8(0); // unk - Always 0 - data << uint8(size); - for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) - data << uint32(*it); - data << updateData.comment; - } + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[0]); + data << uint32(3); + data.WriteByteSeq(guid[7]); + for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) + data << uint32(*it); + SendPacket(&data); } @@ -421,10 +531,10 @@ void WorldSession::SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& roleCheck) // Leader info MUST be sent 1st :S uint64 guid = roleCheck.leader; uint8 roles = roleCheck.roles.find(guid)->second; + Player* player = ObjectAccessor::FindPlayer(guid); data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles - Player* player = ObjectAccessor::FindPlayer(guid); data << uint8(player ? player->getLevel() : 0); // Level for (lfg::LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) @@ -434,10 +544,10 @@ void WorldSession::SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& roleCheck) guid = it->first; roles = it->second; + player = ObjectAccessor::FindPlayer(guid); data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles - player = ObjectAccessor::FindPlayer(guid); data << uint8(player ? player->getLevel() : 0);// Level } } @@ -447,17 +557,76 @@ void WorldSession::SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& roleCheck) void WorldSession::SendLfgJoinResult(lfg::LfgJoinResultData const& joinData) { uint32 size = 0; + ObjectGuid guid = GetPlayer()->GetGUID(); + uint32 queueId = sLFGMgr->GetQueueId(_player->GetGUID()); for (lfg::LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) - size += 8 + 4 + uint32(it->second.size()) * (4 + 4); + size += 8 + 4 + uint32(it->second.size()) * (4 + 4 + 4 + 4); TC_LOG_DEBUG("lfg", "SMSG_LFG_JOIN_RESULT %s checkResult: %u checkValue: %u", GetPlayerInfo().c_str(), joinData.result, joinData.state); WorldPacket data(SMSG_LFG_JOIN_RESULT, 4 + 4 + size); - data << uint32(joinData.result); // Check Result - data << uint32(joinData.state); // Check Value - if (!joinData.lockmap.empty()) - BuildPartyLockDungeonBlock(data, joinData.lockmap); + data << uint32(3); + data << uint8(joinData.result); // Check Result + data << uint32(queueId); // Queue Id + data << uint8(joinData.state); // Check Value + data << uint32(time(NULL)); // Join date + data.WriteBit(guid[2]); + data.WriteBit(guid[7]); + data.WriteBit(guid[3]); + data.WriteBit(guid[0]); + data.WriteBits(joinData.lockmap.size(), 24); + for (lfg::LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) + { + ObjectGuid playerGuid = it->first; + data.WriteBit(playerGuid[7]); + data.WriteBit(playerGuid[5]); + data.WriteBit(playerGuid[3]); + data.WriteBit(playerGuid[6]); + data.WriteBit(playerGuid[0]); + data.WriteBit(playerGuid[2]); + data.WriteBit(playerGuid[4]); + data.WriteBit(playerGuid[1]); + data.WriteBits(it->second.size(), 22); + } + + data.WriteBit(guid[4]); + data.WriteBit(guid[5]); + data.WriteBit(guid[1]); + data.WriteBit(guid[6]); + for (lfg::LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) + { + ObjectGuid playerGuid = it->first; + for (lfg::LfgLockMap::const_iterator itr = it->second.begin(); itr != it->second.end(); ++itr) + { + TC_LOG_TRACE("lfg", "SendLfgJoinResult:: PlayerGUID: " UI64FMTD " DungeonID: %u Lock status: %u Required itemLevel: %u Current itemLevel: %f", + uint64(playerGuid), (itr->first & 0x00FFFFFF), itr->second.lockStatus, itr->second.requiredItemLevel, itr->second.currentItemLevel); + + data << uint32(itr->second.lockStatus); // Lock status + data << uint32(itr->second.currentItemLevel); // Current itemLevel + data << uint32(itr->second.requiredItemLevel); // Required itemLevel + data << uint32(itr->first); // Dungeon entry (id + type) + } + + data.WriteByteSeq(playerGuid[2]); + data.WriteByteSeq(playerGuid[5]); + data.WriteByteSeq(playerGuid[1]); + data.WriteByteSeq(playerGuid[0]); + data.WriteByteSeq(playerGuid[4]); + data.WriteByteSeq(playerGuid[3]); + data.WriteByteSeq(playerGuid[6]); + data.WriteByteSeq(playerGuid[7]); + } + + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[6]); + SendPacket(&data); } @@ -470,17 +639,39 @@ void WorldSession::SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData) queueData.waitTimeTank, queueData.waitTimeHealer, queueData.waitTimeDps, queueData.queuedTime, queueData.tanks, queueData.healers, queueData.dps); - WorldPacket data(SMSG_LFG_QUEUE_STATUS, 4 + 4 + 4 + 4 + 4 +4 + 1 + 1 + 1 + 4); - data << uint32(queueData.dungeonId); // Dungeon - data << int32(queueData.waitTimeAvg); // Average Wait time - data << int32(queueData.waitTime); // Wait Time - data << int32(queueData.waitTimeTank); // Wait Tanks - data << int32(queueData.waitTimeHealer); // Wait Healers - data << int32(queueData.waitTimeDps); // Wait Dps + ObjectGuid guid = _player->GetGUID(); + WorldPacket data(SMSG_LFG_QUEUE_STATUS, 4 + 4 + 4 + 4 + 4 + 4 + 1 + 1 + 1 + 4 + 4 + 4 + 4 + 8); + data.WriteBit(guid[3]); + data.WriteBit(guid[0]); + data.WriteBit(guid[2]); + data.WriteBit(guid[6]); + data.WriteBit(guid[5]); + data.WriteBit(guid[7]); + data.WriteBit(guid[1]); + data.WriteBit(guid[4]); + + data.WriteByteSeq(guid[0]); data << uint8(queueData.tanks); // Tanks needed + data << int32(queueData.waitTimeTank); // Wait Tanks data << uint8(queueData.healers); // Healers needed + data << int32(queueData.waitTimeHealer); // Wait Healers data << uint8(queueData.dps); // Dps needed + data << int32(queueData.waitTimeDps); // Wait Dps + data.WriteByteSeq(guid[4]); + data.WriteByteSeq(guid[6]); + data << int32(queueData.waitTime); // Wait Time + data << uint32(queueData.joinTime); // Join time + data << uint32(queueData.dungeonId); // Dungeon data << uint32(queueData.queuedTime); // Player wait time in queue + data.WriteByteSeq(guid[5]); + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[3]); + data << uint32(queueData.queueId); // Queue Id + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[2]); + data << int32(queueData.waitTimeAvg); // Average Wait time + data << uint32(3); + SendPacket(&data); } @@ -492,29 +683,12 @@ void WorldSession::SendLfgPlayerReward(lfg::LfgPlayerRewardData const& rewardDat TC_LOG_DEBUG("lfg", "SMSG_LFG_PLAYER_REWARD %s rdungeonEntry: %u, sdungeonEntry: %u, done: %u", GetPlayerInfo().c_str(), rewardData.rdungeonEntry, rewardData.sdungeonEntry, rewardData.done); - uint8 itemNum = rewardData.quest->GetRewItemsCount(); + uint8 itemNum = rewardData.quest->GetRewItemsCount() + rewardData.quest->GetRewCurrencyCount(); WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4)); - data << uint32(rewardData.rdungeonEntry); // Random Dungeon Finished - data << uint32(rewardData.sdungeonEntry); // Dungeon Finished - data << uint8(rewardData.done); - data << uint32(1); - data << uint32(rewardData.quest->GetRewOrReqMoney()); - data << uint32(rewardData.quest->XPValue(GetPlayer())); - data << uint32(0); - data << uint32(0); - data << uint8(itemNum); - if (itemNum) - { - for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) - if (uint32 itemId = rewardData.quest->RewardItemId[i]) - { - ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId); - data << uint32(itemId); - data << uint32(item ? item->DisplayInfoID : 0); - data << uint32(rewardData.quest->RewardItemIdCount[i]); - } - } + data << uint32(rewardData.rdungeonEntry); // Random Dungeon Finished + data << uint32(rewardData.sdungeonEntry); // Dungeon Finished + BuildQuestReward(data, rewardData.quest, GetPlayer()); SendPacket(&data); } @@ -540,16 +714,17 @@ void WorldSession::SendLfgBootProposalUpdate(lfg::LfgPlayerBoot const& boot) GetPlayerInfo().c_str(), uint8(boot.inProgress), uint8(playerVote != lfg::LFG_ANSWER_PENDING), uint8(playerVote == lfg::LFG_ANSWER_AGREE), GUID_LOPART(boot.victim), votesNum, agreeNum, secsleft, lfg::LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str()); - WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + boot.reason.length()); - data << uint8(boot.inProgress); // Vote in progress - data << uint8(playerVote != lfg::LFG_ANSWER_PENDING); // Did Vote - data << uint8(playerVote == lfg::LFG_ANSWER_AGREE); // Agree - data << uint64(boot.victim); // Victim GUID - data << uint32(votesNum); // Total Votes - data << uint32(agreeNum); // Agree Count - data << uint32(secsleft); // Time Left - data << uint32(lfg::LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes - data << boot.reason.c_str(); // Kick reason + WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + boot.reason.length()); + data << uint8(boot.inProgress); // Vote in progress + data << uint8(agreeNum >= lfg::LFG_GROUP_KICK_VOTES_NEEDED); // Did succeed + data << uint8(playerVote != lfg::LFG_ANSWER_PENDING); // Did Vote + data << uint8(playerVote == lfg::LFG_ANSWER_AGREE); // Agree + data << uint64(boot.victim); // Victim GUID + data << uint32(votesNum); // Total Votes + data << uint32(agreeNum); // Agree Count + data << uint32(secsleft); // Time Left + data << uint32(lfg::LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes + data << boot.reason.c_str(); // Kick reason SendPacket(&data); } @@ -559,6 +734,8 @@ void WorldSession::SendLfgUpdateProposal(lfg::LfgProposal const& proposal) uint64 gguid = proposal.players.find(guid)->second.group; bool silent = !proposal.isNew && gguid == proposal.group; uint32 dungeonEntry = proposal.dungeonId; + uint32 queueId = sLFGMgr->GetQueueId(_player->GetGUID()); + time_t joinTime = sLFGMgr->GetQueueJoinTime(_player->GetGUID()); TC_LOG_DEBUG("lfg", "SMSG_LFG_PROPOSAL_UPDATE %s state: %u", GetPlayerInfo().c_str(), proposal.state); @@ -574,31 +751,81 @@ void WorldSession::SendLfgUpdateProposal(lfg::LfgProposal const& proposal) dungeonEntry = sLFGMgr->GetLFGDungeonEntry(dungeonEntry); WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + proposal.players.size() * (4 + 1 + 1 + 1 + 1 +1)); + data << uint32(joinTime); + data << uint32(proposal.encounters); // Encounters done + data << uint32(queueId); // Queue Id + data << uint32(3); // Always 3 data << uint32(dungeonEntry); // Dungeon - data << uint8(proposal.state); // Proposal state - data << uint32(proposal.id); // Proposal ID - data << uint32(proposal.encounters); // encounters done - data << uint8(silent); // Show proposal window - data << uint8(proposal.players.size()); // Group size + data << uint32(proposal.id); // Proposal Id + data << uint8(proposal.state); // State + + ObjectGuid guid1 = guid; + ObjectGuid guid2 = gguid; + + data.WriteBit(guid2[4]); + data.WriteBit(guid1[3]); + data.WriteBit(guid1[7]); + data.WriteBit(guid1[0]); + data.WriteBit(guid2[1]); + data.WriteBit(silent); + data.WriteBit(guid1[4]); + data.WriteBit(guid1[5]); + data.WriteBit(guid2[3]); + data.WriteBits(proposal.players.size(), 23); + data.WriteBit(guid2[7]); for (lfg::LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) { lfg::LfgProposalPlayer const& player = it->second; - data << uint32(player.role); // Role - data << uint8(it->first == guid); // Self player - if (!player.group) // Player not it a group + + if (!player.group) { - data << uint8(0); // Not in dungeon - data << uint8(0); // Not same group + data.WriteBit(0); + data.WriteBit(0); } else { - data << uint8(player.group == proposal.group); // In dungeon (silent) - data << uint8(player.group == gguid); // Same Group than player + data.WriteBit(player.group == proposal.group); // Is group in dungeon + data.WriteBit(player.group == gguid); // Same group as the player } - data << uint8(player.accept != lfg::LFG_ANSWER_PENDING);// Answered - data << uint8(player.accept == lfg::LFG_ANSWER_AGREE); // Accepted + + data.WriteBit(player.accept == lfg::LFG_ANSWER_AGREE); + data.WriteBit(player.accept != lfg::LFG_ANSWER_PENDING); + data.WriteBit(it->first == guid); } + + data.WriteBit(guid2[5]); + data.WriteBit(guid1[6]); + data.WriteBit(guid2[2]); + data.WriteBit(guid2[6]); + data.WriteBit(guid1[2]); + data.WriteBit(guid1[1]); + data.WriteBit(guid2[0]); + + data.WriteByteSeq(guid1[5]); + data.WriteByteSeq(guid2[3]); + data.WriteByteSeq(guid2[6]); + data.WriteByteSeq(guid1[6]); + data.WriteByteSeq(guid1[0]); + data.WriteByteSeq(guid2[5]); + data.WriteByteSeq(guid1[1]); + + for (lfg::LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) + { + lfg::LfgProposalPlayer const& player = it->second; + data << uint32(player.role); + } + + data.WriteByteSeq(guid2[7]); + data.WriteByteSeq(guid1[4]); + data.WriteByteSeq(guid2[0]); + data.WriteByteSeq(guid2[1]); + data.WriteByteSeq(guid1[2]); + data.WriteByteSeq(guid1[7]); + data.WriteByteSeq(guid2[2]); + data.WriteByteSeq(guid1[3]); + data.WriteByteSeq(guid2[4]); + SendPacket(&data); } diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index b9c6f349ac3..7c3d9e99eee 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -22,6 +22,7 @@ #include "Creature.h" #include "GameObject.h" #include "Group.h" +#include "GuildMgr.h" #include "LootMgr.h" #include "ObjectAccessor.h" #include "Object.h" @@ -186,6 +187,10 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) (*i)->ModifyMoney(goldPerPlayer); (*i)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer); + if (Guild* guild = sGuildMgr->GetGuildById((*i)->GetGuildId())) + if (uint32 guildGold = CalculatePct(goldPerPlayer, (*i)->GetTotalAuraModifier(SPELL_AURA_DEPOSIT_BONUS_MONEY_IN_GUILD_BANK_ON_LOOT))) + guild->HandleMemberDepositMoney(this, guildGold, true); + WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); data << uint32(goldPerPlayer); data << uint8(playersNear.size() <= 1); // Controls the text displayed in chat. 0 is "Your share is..." and 1 is "You loot..." @@ -197,6 +202,10 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) player->ModifyMoney(loot->gold); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, loot->gold); + if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) + if (uint32 guildGold = CalculatePct(loot->gold, player->GetTotalAuraModifier(SPELL_AURA_DEPOSIT_BONUS_MONEY_IN_GUILD_BANK_ON_LOOT))) + guild->HandleMemberDepositMoney(this, guildGold, true); + WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); data << uint32(loot->gold); data << uint8(1); // "You loot..." @@ -447,7 +456,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData) ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (item.follow_loot_rules && !item.AllowedForPlayer(target)) - msg = EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + msg = EQUIP_ERR_CANT_EQUIP_EVER; if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); @@ -463,7 +472,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData) Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); - target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item.count); + target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, item.itemid, item.count, loot->loot_type); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index 1270f4e6419..1359032080b 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -28,6 +28,8 @@ #include "DBCStores.h" #include "Item.h" #include "AccountMgr.h" +#include "BattlenetAccountMgr.h" +#include "GuildMgr.h" bool WorldSession::CanOpenMailBox(uint64 guid) { @@ -57,15 +59,20 @@ bool WorldSession::CanOpenMailBox(uint64 guid) void WorldSession::HandleSendMail(WorldPacket& recvData) { - uint64 mailbox, unk3; + ObjectGuid mailbox; + uint64 money, COD; std::string receiverName, subject, body; - uint32 unk1, unk2, money, COD; - uint8 unk4; - uint8 items_count; - recvData >> mailbox >> receiverName >> subject >> body - >> unk1 // stationery? - >> unk2 // 0x00000000 - >> items_count; // attached items count + uint32 bodyLength, subjectLength, receiverLength; + uint32 unk1, unk2; + + recvData >> unk1; + recvData >> unk2; // Stationery? + + recvData >> COD >> money; // money and cod + bodyLength = recvData.ReadBits(12); + subjectLength = recvData.ReadBits(9); + + uint8 items_count = recvData.ReadBits(5); // attached items count if (items_count > MAX_MAIL_ITEMS) // client limit { @@ -74,17 +81,60 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - uint64 itemGUIDs[MAX_MAIL_ITEMS]; + mailbox[0] = recvData.ReadBit(); + + ObjectGuid itemGUIDs[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { - recvData.read_skip<uint8>(); // item slot in mail, not used - recvData >> itemGUIDs[i]; + itemGUIDs[i][2] = recvData.ReadBit(); + itemGUIDs[i][6] = recvData.ReadBit(); + itemGUIDs[i][3] = recvData.ReadBit(); + itemGUIDs[i][7] = recvData.ReadBit(); + itemGUIDs[i][1] = recvData.ReadBit(); + itemGUIDs[i][0] = recvData.ReadBit(); + itemGUIDs[i][4] = recvData.ReadBit(); + itemGUIDs[i][5] = recvData.ReadBit(); } - recvData >> money >> COD; // money and cod - recvData >> unk3; // const 0 - recvData >> unk4; // const 0 + mailbox[3] = recvData.ReadBit(); + mailbox[4] = recvData.ReadBit(); + receiverLength = recvData.ReadBits(7); + mailbox[2] = recvData.ReadBit(); + mailbox[6] = recvData.ReadBit(); + mailbox[1] = recvData.ReadBit(); + mailbox[7] = recvData.ReadBit(); + mailbox[5] = recvData.ReadBit(); + + recvData.ReadByteSeq(mailbox[4]); + + for (uint8 i = 0; i < items_count; ++i) + { + recvData.ReadByteSeq(itemGUIDs[i][6]); + recvData.ReadByteSeq(itemGUIDs[i][1]); + recvData.ReadByteSeq(itemGUIDs[i][7]); + recvData.ReadByteSeq(itemGUIDs[i][2]); + recvData.read_skip<uint8>(); // item slot in mail, not used + recvData.ReadByteSeq(itemGUIDs[i][3]); + recvData.ReadByteSeq(itemGUIDs[i][0]); + recvData.ReadByteSeq(itemGUIDs[i][4]); + recvData.ReadByteSeq(itemGUIDs[i][5]); + } + + recvData.ReadByteSeq(mailbox[7]); + recvData.ReadByteSeq(mailbox[3]); + recvData.ReadByteSeq(mailbox[6]); + recvData.ReadByteSeq(mailbox[5]); + + subject = recvData.ReadString(subjectLength); + receiverName = recvData.ReadString(receiverLength); + + recvData.ReadByteSeq(mailbox[2]); + recvData.ReadByteSeq(mailbox[0]); + + body = recvData.ReadString(bodyLength); + + recvData.ReadByteSeq(mailbox[1]); // packet read complete, now do check @@ -109,7 +159,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) if (!receiverGuid) { TC_LOG_INFO("network", "Player %u is sending mail to %s (GUID: not existed!) with subject %s " - "and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", + "and body %s includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiverName.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); @@ -117,7 +167,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } TC_LOG_INFO("network", "Player %u is sending mail to %s (GUID: %u) with subject %s and body %s " - "includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", + "includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiverName.c_str(), GUID_LOPART(receiverGuid), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); @@ -129,7 +179,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client - uint32 reqmoney = cost + money; + uint64 reqmoney = cost + money; // Check for overflow if (reqmoney < money) @@ -150,6 +200,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) uint8 mailsCount = 0; //do not allow to send to one player more than 100 mails uint8 receiverLevel = 0; uint32 receiverAccountId = 0; + uint32 receiverBnetAccountId = 0; if (receiver) { @@ -157,6 +208,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) mailsCount = receiver->GetMailSize(); receiverLevel = receiver->getLevel(); receiverAccountId = receiver->GetSession()->GetAccountId(); + receiverBnetAccountId = receiver->GetSession()->GetBattlenetAccountId(); } else { @@ -183,6 +235,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } receiverAccountId = sObjectMgr->GetPlayerAccountIdByGUID(receiverGuid); + receiverBnetAccountId = Battlenet::AccountMgr::GetIdByGameAccount(receiverAccountId); } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. @@ -246,8 +299,11 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != receiverAccountId) { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); - return; + if (!item->IsBattlenetAccountBound() || !player->GetSession()->GetBattlenetAccountId() || player->GetSession()->GetBattlenetAccountId() != receiverBnetAccountId) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_NOT_SAME_ACCOUNT); + return; + } } if (item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) @@ -264,7 +320,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) if (item->IsNotEmptyBag()) { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS); + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_DESTROY_NONEMPTY_BAG); return; } @@ -273,7 +329,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) player->SendMailResult(0, MAIL_SEND, MAIL_OK); - player->ModifyMoney(-int32(reqmoney)); + player->ModifyMoney(-int64(reqmoney)); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; @@ -314,7 +370,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) if (log && money > 0) { - sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail money: %u to player: %s (GUID: %u) (Account: %u)", + sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail money: " UI64FMTD " to player: %s (GUID: %u) (Account: %u)", GetPlayerName().c_str(), GetGuidLow(), GetAccountId(), money, receiverName.c_str(), GUID_LOPART(receiverGuid), receiverAccountId); } } @@ -322,6 +378,11 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; + // Mail sent between guild members arrives instantly if they have the guild perk "Guild Mail" + if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) + if (guild->GetLevel() >= 17 && guild->IsMember(receiverGuid)) + deliver_delay = 0; + // don't ask for COD if there are no items if (items_count == 0) COD = 0; @@ -406,8 +467,7 @@ void WorldSession::HandleMailReturnToSender(WorldPacket& recvData) player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR); return; } - //we can return mail now - //so firstly delete the old one + //we can return mail now, so firstly delete the old one SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); @@ -431,14 +491,8 @@ void WorldSession::HandleMailReturnToSender(WorldPacket& recvData) { for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) { - Item* item = player->GetMItem(itr2->item_guid); - if (item) + if (Item* const item = player->GetMItem(itr2->item_guid)) draft.AddItem(item); - else - { - //WTF? - } - player->RemoveMItem(itr2->item_guid); } } @@ -481,7 +535,7 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) } // prevent cheating with skip client money check - if (!player->HasEnoughMoney(m->COD)) + if (!player->HasEnoughMoney(uint64(m->COD))) { player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); return; @@ -520,7 +574,7 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) if (!sObjectMgr->GetPlayerNameByGUID(sender_guid, sender_name)) sender_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); } - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) receiver mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)", + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) receiver mail item: %s (Entry: %u Count: %u) and send COD money: " UI64FMTD " to player: %s (Account: %u)", GetPlayerName().c_str(), GetAccountId(), it->GetTemplate()->Name1.c_str(), it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId); } else if (!receiver) @@ -558,9 +612,12 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) { uint64 mailbox; + uint64 money; uint32 mailId; + recvData >> mailbox; recvData >> mailId; + recvData >> money; if (!CanOpenMailBox(mailbox)) return; @@ -568,7 +625,8 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) Player* player = _player; Mail* m = player->GetMail(mailId); - if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + if ((!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) || + (money > 0 && m->money != money)) { player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; @@ -614,7 +672,7 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData) uint32 mailsCount = 0; // real send to client mails amount uint32 realCount = 0; // real mails amount - WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size + WorldPacket data(SMSG_MAIL_LIST_RESULT, 200); // guess size data << uint32(0); // real mail's count data << uint8(0); // mail's count time_t cur_time = time(NULL); @@ -655,14 +713,14 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData) case MAIL_GAMEOBJECT: case MAIL_AUCTION: case MAIL_CALENDAR: - data << uint32((*itr)->sender); // creature/gameobject entry, auction id, calendar event id? + data << uint32((*itr)->sender); // creature/gameobject entry, auction id, calendar event id? break; } - data << uint32((*itr)->COD); // COD - data << uint32(0); // package (Package.dbc) + data << uint64((*itr)->COD); // COD + data << uint32(0); // Package.dbc ID ? data << uint32((*itr)->stationery); // stationery (Stationery.dbc) - data << uint32((*itr)->money); // Gold + data << uint64((*itr)->money); // Gold data << uint32((*itr)->checked); // flags data << float(float((*itr)->expire_time-time(NULL))/DAY); // Time data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) @@ -685,6 +743,7 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData) data << uint32((item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0)); data << uint32((item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0)); } + // can be negative data << int32((item ? item->GetItemRandomPropertyId() : 0)); // unk @@ -751,7 +810,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) return; } - bodyItem->SetText(mailTemplateEntry->content[GetSessionDbcLocale()]); + bodyItem->SetText(mailTemplateEntry->content); } else bodyItem->SetText(m->body); @@ -780,7 +839,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) } /// @todo Fix me! ... this void has probably bad condition, but good data are sent -void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recvData*/) +void WorldSession::HandleQueryNextMailTime(WorldPacket& /*recvData*/) { WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 8); @@ -832,3 +891,10 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recvData*/) SendPacket(&data); } + +void WorldSession::SendShowMailBox(uint64 guid) +{ + WorldPacket data(SMSG_SHOW_MAILBOX, 8); + data << guid; + SendPacket(&data); +} diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index baa20f76a40..c9891de3c16 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -55,6 +55,7 @@ #include "BattlegroundMgr.h" #include "Battlefield.h" #include "BattlefieldMgr.h" +#include "DB2Stores.h" void WorldSession::HandleRepopRequestOpcode(WorldPacket& recvData) { @@ -388,7 +389,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/) uint32 reason = 0; if (GetPlayer()->IsInCombat() && !canLogoutInCombat) reason = 1; - else if (GetPlayer()->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING | MOVEMENTFLAG_FALLING_FAR)) + else if (GetPlayer()->IsFalling()) reason = 3; // is jumping or falling else if (GetPlayer()->duel || GetPlayer()->HasAura(9454)) // is dueling or frozen by GM via freeze command reason = 2; // FIXME - Need the correct value @@ -404,7 +405,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/) return; } - //instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf + // instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf if (instantLogout) { LogoutPlayer(true); @@ -415,11 +416,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/) if (GetPlayer()->CanFreeMove()) { GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT); - - WorldPacket data(SMSG_FORCE_MOVE_ROOT, (8+4)); // guess size - data.append(GetPlayer()->GetPackGUID()); - data << (uint32)2; - SendPacket(&data); + GetPlayer()->SetRooted(true); GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); } @@ -448,10 +445,7 @@ void WorldSession::HandleLogoutCancelOpcode(WorldPacket& /*recvData*/) if (GetPlayer()->CanFreeMove()) { //!we can move again - data.Initialize(SMSG_FORCE_MOVE_UNROOT, 8); // guess size - data.append(GetPlayer()->GetPackGUID()); - data << uint32(0); - SendPacket(&data); + GetPlayer()->SetRooted(false); //! Stand Up GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND); @@ -507,6 +501,13 @@ void WorldSession::HandleZoneUpdateOpcode(WorldPacket& recvData) //GetPlayer()->SendInitWorldStates(true, newZone); } +void WorldSession::HandleReturnToGraveyard(WorldPacket& /*recvPacket*/) +{ + if (GetPlayer()->IsAlive() || !GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + return; + GetPlayer()->RepopAtGraveyard(); +} + void WorldSession::HandleSetSelectionOpcode(WorldPacket& recvData) { uint64 guid; @@ -526,9 +527,8 @@ void WorldSession::HandleStandStateChangeOpcode(WorldPacket& recvData) void WorldSession::HandleContactListOpcode(WorldPacket& recvData) { - uint32 unk; - recvData >> unk; - TC_LOG_DEBUG("network", "WORLD: Received CMSG_CONTACT_LIST - Unk: %d", unk); + recvData.read_skip<uint32>(); // always 1 + TC_LOG_DEBUG("network", "WORLD: Received CMSG_CONTACT_LIST"); _player->GetSocial()->SendSocialList(_player); } @@ -713,9 +713,11 @@ void WorldSession::HandleBugOpcode(WorldPacket& recvData) uint32 suggestion, contentlen, typelen; std::string content, type; - recvData >> suggestion >> contentlen >> content; + recvData >> suggestion >> contentlen; + content = recvData.ReadString(contentlen); - recvData >> typelen >> type; + recvData >> typelen; + type = recvData.ReadString(typelen); if (suggestion == 0) TC_LOG_DEBUG("network", "WORLD: Received CMSG_BUG [Bug Report]"); @@ -784,11 +786,11 @@ void WorldSession::HandleResurrectResponseOpcode(WorldPacket& recvData) if (status == 0) { - GetPlayer()->clearResurrectRequestData(); // reject + GetPlayer()->ClearResurrectRequestData(); // reject return; } - if (!GetPlayer()->isResurrectRequestedBy(guid)) + if (!GetPlayer()->IsResurrectRequestedBy(guid)) return; GetPlayer()->ResurrectUsingRequestData(); @@ -922,7 +924,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recvData) if (pvp->HandleAreaTrigger(_player, triggerId)) return; - AreaTrigger const* at = sObjectMgr->GetAreaTrigger(triggerId); + AreaTriggerStruct const* at = sObjectMgr->GetAreaTrigger(triggerId); if (!at) return; @@ -1034,6 +1036,13 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recvData) SendPacket(&data); } +int32 WorldSession::HandleEnableNagleAlgorithm() +{ + // Instructs the server we wish to receive few amounts of large packets (SMSG_MULTIPLE_PACKETS?) + // instead of large amount of small packets + return 0; +} + void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recvData) { uint8 button; @@ -1059,12 +1068,32 @@ void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recvData*/) void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData) { - /* WorldSession::Update(getMSTime());*/ TC_LOG_DEBUG("network", "WORLD: Received CMSG_MOVE_TIME_SKIPPED"); - uint64 guid; - recvData.readPackGUID(guid); - recvData.read_skip<uint32>(); + ObjectGuid guid; + uint32 time; + recvData >> time; + + guid[5] = recvData.ReadBit(); + guid[1] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + guid[6] = recvData.ReadBit(); + guid[0] = recvData.ReadBit(); + guid[4] = recvData.ReadBit(); + guid[2] = recvData.ReadBit(); + + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[1]); + recvData.ReadByteSeq(guid[2]); + recvData.ReadByteSeq(guid[4]); + recvData.ReadByteSeq(guid[3]); + recvData.ReadByteSeq(guid[6]); + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[5]); + + //TODO! + /* uint64 guid; uint32 time_skipped; @@ -1185,10 +1214,9 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData) if (GetPlayer()->IsValidAttackTarget(player)) return; - uint32 talent_points = 0x47; - uint32 guid_size = player->GetPackGUID().wpos(); - WorldPacket data(SMSG_INSPECT_TALENT, guid_size+4+talent_points); - data.append(player->GetPackGUID()); + uint32 talent_points = 41; + WorldPacket data(SMSG_INSPECT_TALENT, 8 + 4 + 1 + 1 + talent_points + 8 + 4 + 8 + 4); + data << player->GetGUID(); if (sWorld->getBoolConfig(CONFIG_TALENTS_INSPECTING) || _player->IsGameMaster()) player->BuildPlayerTalentsInfoData(&data); @@ -1200,19 +1228,40 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData) } player->BuildEnchantmentsInfoData(&data); + if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) + { + data << uint64(guild->GetGUID()); + data << uint32(guild->GetLevel()); + data << uint64(guild->GetExperience()); + data << uint32(guild->GetMembersCount()); + } SendPacket(&data); } void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recvData) { - uint64 guid; - recvData >> guid; - + ObjectGuid guid; + guid[1] = recvData.ReadBit(); + guid[5] = recvData.ReadBit(); + guid[7] = recvData.ReadBit(); + guid[3] = recvData.ReadBit(); + guid[2] = recvData.ReadBit(); + guid[4] = recvData.ReadBit(); + guid[0] = recvData.ReadBit(); + guid[6] = recvData.ReadBit(); + + recvData.ReadByteSeq(guid[4]); + recvData.ReadByteSeq(guid[7]); + recvData.ReadByteSeq(guid[0]); + recvData.ReadByteSeq(guid[5]); + recvData.ReadByteSeq(guid[1]); + recvData.ReadByteSeq(guid[6]); + recvData.ReadByteSeq(guid[2]); + recvData.ReadByteSeq(guid[3]); Player* player = ObjectAccessor::FindPlayer(guid); - if (!player) { - TC_LOG_DEBUG("network", "MSG_INSPECT_HONOR_STATS: No player found from GUID: " UI64FMTD, guid); + TC_LOG_DEBUG("network", "CMSG_INSPECT_HONOR_STATS: No player found from GUID: " UI64FMTD, (uint64)guid); return; } @@ -1222,13 +1271,28 @@ void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recvData) if (GetPlayer()->IsValidAttackTarget(player)) return; - WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4); - data << uint64(player->GetGUID()); - data << uint8(player->GetHonorPoints()); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION)); + ObjectGuid playerGuid = player->GetGUID(); + WorldPacket data(SMSG_INSPECT_HONOR_STATS, 8+1+4+4); + data.WriteBit(playerGuid[4]); + data.WriteBit(playerGuid[3]); + data.WriteBit(playerGuid[6]); + data.WriteBit(playerGuid[2]); + data.WriteBit(playerGuid[5]); + data.WriteBit(playerGuid[0]); + data.WriteBit(playerGuid[7]); + data.WriteBit(playerGuid[1]); + data << uint8(0); // rank + data << uint16(player->GetUInt16Value(PLAYER_FIELD_KILLS, 1)); // yesterday kills + data << uint16(player->GetUInt16Value(PLAYER_FIELD_KILLS, 0)); // today kills + data.WriteByteSeq(playerGuid[2]); + data.WriteByteSeq(playerGuid[0]); + data.WriteByteSeq(playerGuid[6]); + data.WriteByteSeq(playerGuid[3]); + data.WriteByteSeq(playerGuid[4]); + data.WriteByteSeq(playerGuid[1]); + data.WriteByteSeq(playerGuid[5]); data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); + data.WriteByteSeq(playerGuid[7]); SendPacket(&data); } @@ -1360,8 +1424,9 @@ void WorldSession::HandleComplainOpcode(WorldPacket& recvData) // if it's mail spam - ALL mails from this spammer automatically removed by client // Complaint Received message - WorldPacket data(SMSG_COMPLAIN_RESULT, 1); - data << uint8(0); + WorldPacket data(SMSG_COMPLAIN_RESULT, 2); + data << uint8(0); // value 1 resets CGChat::m_complaintsSystemStatus in client. (unused?) + data << uint8(0); // value 0xC generates a "CalendarError" in client. SendPacket(&data); TC_LOG_DEBUG("network", "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()); @@ -1437,8 +1502,8 @@ void WorldSession::HandleTimeSyncResp(WorldPacket& recvData) uint32 counter, clientTicks; recvData >> counter >> clientTicks; - if (counter != _player->m_timeSyncCounter - 1) - TC_LOG_DEBUG("network", "Wrong time sync counter from player %s (cheater?)", _player->GetName().c_str()); + if (counter != _player->m_timeSyncQueue.front()) + TC_LOG_ERROR("network", "Wrong time sync counter from player %s (cheater?)", _player->GetName().c_str()); TC_LOG_DEBUG("network", "Time sync received: counter %u, client ticks %u, time since last sync %u", counter, clientTicks, clientTicks - _player->m_timeSyncClient); @@ -1448,6 +1513,7 @@ void WorldSession::HandleTimeSyncResp(WorldPacket& recvData) TC_LOG_DEBUG("network", "Our ticks: %u, diff %u, latency %u", ourTicks, ourTicks - clientTicks, GetLatency()); _player->m_timeSyncClient = clientTicks; + _player->m_timeSyncQueue.pop(); } void WorldSession::HandleResetInstancesOpcode(WorldPacket& /*recvData*/) @@ -1604,16 +1670,8 @@ void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData) // fly mode on/off TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); - uint64 guid; // guid - unused - recvData.readPackGUID(guid); - - recvData.read_skip<uint32>(); // unk - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recvData, &movementInfo); - - recvData.read_skip<float>(); // unk2 + _player->ReadMovementInfo(recvData, &movementInfo); _player->m_mover->m_movementInfo.flags = movementInfo.GetMovementFlags(); } @@ -1657,6 +1715,15 @@ void WorldSession::HandleQueryInspectAchievements(WorldPacket& recvData) player->SendRespondInspectAchievements(_player); } +void WorldSession::HandleGuildAchievementProgressQuery(WorldPacket& recvData) +{ + uint32 achievementId; + recvData >> achievementId; + + if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId())) + guild->GetAchievementMgr().SendAchievementInfo(_player, achievementId); +} + void WorldSession::HandleWorldStateUITimerUpdate(WorldPacket& /*recvData*/) { // empty opcode @@ -1675,12 +1742,54 @@ void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recvData*/) SendAccountDataTimes(GLOBAL_CACHE_MASK); } -void WorldSession::SendSetPhaseShift(uint32 PhaseShift) +void WorldSession::SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps, std::set<uint32> const& worldMapAreaSwaps) { - WorldPacket data(SMSG_SET_PHASE_SHIFT, 4); - data << uint32(PhaseShift); + ObjectGuid guid = _player->GetGUID(); + + WorldPacket data(SMSG_SET_PHASE_SHIFT, 1 + 8 + 4 + 4 + 4 + 4 + 2 * phaseIds.size() + 4 + terrainswaps.size() * 2); + data.WriteBit(guid[2]); + data.WriteBit(guid[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[6]); + data.WriteBit(guid[4]); + data.WriteBit(guid[5]); + data.WriteBit(guid[0]); + data.WriteBit(guid[7]); + + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[4]); + + data << uint32(worldMapAreaSwaps.size()); + for (auto mapSwap : worldMapAreaSwaps) + data << uint16(mapSwap); // WorldMapArea.dbc id (controls map display) + + data.WriteByteSeq(guid[1]); + + data << uint32(phaseIds.size() ? 0 : 8); // flags (not phasemask) + + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[6]); + + data << uint32(0); // Inactive terrain swaps + //for (uint8 i = 0; i < inactiveSwapsCount; ++i) + // data << uint16(0); + + data << uint32(phaseIds.size()) * 2; // Phase.dbc ids + for (std::set<uint32>::const_iterator itr = phaseIds.begin(); itr != phaseIds.end(); ++itr) + data << uint16(*itr); + + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[0]); + + data << uint32(terrainswaps.size()) * 2; // Active terrain swaps + for (std::set<uint32>::const_iterator itr = terrainswaps.begin(); itr != terrainswaps.end(); ++itr) + data << uint16(*itr); + + data.WriteByteSeq(guid[5]); + SendPacket(&data); } + // Battlefield and Battleground void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket& recvData) { @@ -1768,6 +1877,74 @@ void WorldSession::HandleInstanceLockResponse(WorldPacket& recvPacket) _player->SetPendingBind(0, 0); } +void WorldSession::HandleRequestHotfix(WorldPacket& recvPacket) +{ + uint32 type, count; + recvPacket >> type; + + DB2StorageBase const* store = GetDB2Storage(type); + if (!store) + { + TC_LOG_ERROR("network", "CMSG_REQUEST_HOTFIX: Received unknown hotfix type: %u", type); + recvPacket.rfinish(); + return; + } + + count = recvPacket.ReadBits(23); + + ObjectGuid* guids = new ObjectGuid[count]; + for (uint32 i = 0; i < count; ++i) + { + guids[i][0] = recvPacket.ReadBit(); + guids[i][4] = recvPacket.ReadBit(); + guids[i][7] = recvPacket.ReadBit(); + guids[i][2] = recvPacket.ReadBit(); + guids[i][5] = recvPacket.ReadBit(); + guids[i][3] = recvPacket.ReadBit(); + guids[i][6] = recvPacket.ReadBit(); + guids[i][1] = recvPacket.ReadBit(); + } + + uint32 entry; + for (uint32 i = 0; i < count; ++i) + { + recvPacket.ReadByteSeq(guids[i][5]); + recvPacket.ReadByteSeq(guids[i][6]); + recvPacket.ReadByteSeq(guids[i][7]); + recvPacket.ReadByteSeq(guids[i][0]); + recvPacket.ReadByteSeq(guids[i][1]); + recvPacket.ReadByteSeq(guids[i][3]); + recvPacket.ReadByteSeq(guids[i][4]); + recvPacket >> entry; + recvPacket.ReadByteSeq(guids[i][2]); + + if (!store->HasRecord(entry)) + { + WorldPacket data(SMSG_DB_REPLY, 4 * 4); + data << -int32(entry); + data << uint32(store->GetHash()); + data << uint32(time(NULL)); + data << uint32(0); + SendPacket(&data); + continue; + } + + WorldPacket data(SMSG_DB_REPLY); + data << int32(entry); + data << uint32(store->GetHash()); + data << uint32(sObjectMgr->GetHotfixDate(entry, store->GetHash())); + + size_t sizePos = data.wpos(); + data << uint32(0); // size of next block + store->WriteRecord(entry, uint32(GetSessionDbcLocale()), data); + data.put<uint32>(sizePos, data.wpos() - sizePos - 4); + + SendPacket(&data); + } + + delete[] guids; +} + void WorldSession::HandleUpdateMissileTrajectory(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "WORLD: CMSG_UPDATE_MISSILE_TRAJECTORY"); @@ -1807,7 +1984,179 @@ void WorldSession::HandleUpdateMissileTrajectory(WorldPacket& recvPacket) { uint32 opcode; recvPacket >> opcode; - recvPacket.SetOpcode(opcode); + recvPacket.SetOpcode(MSG_MOVE_STOP); // always set to MSG_MOVE_STOP in client SetOpcode HandleMovementOpcodes(recvPacket); } } + +void WorldSession::HandleViolenceLevel(WorldPacket& recvPacket) +{ + uint8 violenceLevel; + recvPacket >> violenceLevel; + + // do something? +} + +void WorldSession::HandleObjectUpdateFailedOpcode(WorldPacket& recvPacket) +{ + ObjectGuid guid; + guid[6] = recvPacket.ReadBit(); + guid[7] = recvPacket.ReadBit(); + guid[4] = recvPacket.ReadBit(); + guid[0] = recvPacket.ReadBit(); + guid[1] = recvPacket.ReadBit(); + guid[5] = recvPacket.ReadBit(); + guid[3] = recvPacket.ReadBit(); + guid[2] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guid[6]); + recvPacket.ReadByteSeq(guid[7]); + recvPacket.ReadByteSeq(guid[2]); + recvPacket.ReadByteSeq(guid[3]); + recvPacket.ReadByteSeq(guid[1]); + recvPacket.ReadByteSeq(guid[4]); + recvPacket.ReadByteSeq(guid[0]); + recvPacket.ReadByteSeq(guid[5]); + + WorldObject* obj = ObjectAccessor::GetWorldObject(*GetPlayer(), guid); + TC_LOG_ERROR("network", "Object update failed for object " UI64FMTD " (%s) for player %s (%u)", uint64(guid), obj ? obj->GetName().c_str() : "object-not-found", GetPlayerName().c_str(), GetGuidLow()); + + // If create object failed for current player then client will be stuck on loading screen + if (_player->GetGUID() == guid) + { + LogoutPlayer(true); + return; + } + + // Pretend we've never seen this object + _player->m_clientGUIDs.erase(guid); +} + +void WorldSession::HandleSaveCUFProfiles(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_SAVE_CUF_PROFILES"); + + uint8 count = (uint8)recvPacket.ReadBits(20); + + if (count > MAX_CUF_PROFILES) + { + TC_LOG_ERROR("entities.player", "HandleSaveCUFProfiles - %s tried to save more than %i CUF profiles. Hacking attempt?", GetPlayerName().c_str(), MAX_CUF_PROFILES); + recvPacket.rfinish(); + return; + } + + CUFProfile* profiles[MAX_CUF_PROFILES]; + uint8 strlens[MAX_CUF_PROFILES]; + + for (uint8 i = 0; i < count; ++i) + { + profiles[i] = new CUFProfile; + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_SPEC_2 , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_10_PLAYERS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_UNK_157 , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_HEAL_PREDICTION , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_SPEC_1 , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_PVP , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_POWER_BAR , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_15_PLAYERS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_40_PLAYERS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_PETS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_5_PLAYERS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_ONLY_DISPELLABLE_DEBUFFS, recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_2_PLAYERS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_UNK_156 , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_NON_BOSS_DEBUFFS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_MAIN_TANK_AND_ASSIST , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_AGGRO_HIGHLIGHT , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_3_PLAYERS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_BORDER , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_USE_CLASS_COLORS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_UNK_145 , recvPacket.ReadBit()); + strlens[i] = (uint8)recvPacket.ReadBits(8); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_PVE , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_DISPLAY_HORIZONTAL_GROUPS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_25_PLAYERS , recvPacket.ReadBit()); + profiles[i]->BoolOptions.set(CUF_KEEP_GROUPS_TOGETHER , recvPacket.ReadBit()); + } + + for (uint8 i = 0; i < count; ++i) + { + recvPacket >> profiles[i]->Unk146; + profiles[i]->ProfileName = recvPacket.ReadString(strlens[i]); + recvPacket >> profiles[i]->Unk152; + recvPacket >> profiles[i]->FrameHeight; + recvPacket >> profiles[i]->FrameWidth; + recvPacket >> profiles[i]->Unk150; + recvPacket >> profiles[i]->HealthText; + recvPacket >> profiles[i]->Unk147; + recvPacket >> profiles[i]->SortBy; + recvPacket >> profiles[i]->Unk154; + recvPacket >> profiles[i]->Unk148; + + GetPlayer()->SaveCUFProfile(i, profiles[i]); + } + + for (uint8 i = count; i < MAX_CUF_PROFILES; ++i) + GetPlayer()->SaveCUFProfile(i, NULL); +} + +void WorldSession::SendLoadCUFProfiles() +{ + Player* player = GetPlayer(); + + uint8 count = player->GetCUFProfilesCount(); + + ByteBuffer byteBuffer(25 * count); + WorldPacket data(SMSG_LOAD_CUF_PROFILES, 5 * count + 25 * count); + + data.WriteBits(count, 20); + for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) + { + CUFProfile* profile = player->GetCUFProfile(i); + if (!profile) + continue; + + data.WriteBit(profile->BoolOptions[CUF_UNK_157]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_10_PLAYERS]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_5_PLAYERS]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_25_PLAYERS]); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_HEAL_PREDICTION]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_PVE]); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_HORIZONTAL_GROUPS]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_40_PLAYERS]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_3_PLAYERS]); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_AGGRO_HIGHLIGHT]); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_BORDER]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_2_PLAYERS]); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_NON_BOSS_DEBUFFS]); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_MAIN_TANK_AND_ASSIST]); + data.WriteBit(profile->BoolOptions[CUF_UNK_156]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_SPEC_2]); + data.WriteBit(profile->BoolOptions[CUF_USE_CLASS_COLORS]); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_POWER_BAR]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_SPEC_1]); + data.WriteBits(profile->ProfileName.size(), 8); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_ONLY_DISPELLABLE_DEBUFFS]); + data.WriteBit(profile->BoolOptions[CUF_KEEP_GROUPS_TOGETHER]); + data.WriteBit(profile->BoolOptions[CUF_UNK_145]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_15_PLAYERS]); + data.WriteBit(profile->BoolOptions[CUF_DISPLAY_PETS]); + data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_PVP]); + + byteBuffer << uint16(profile->Unk154); + byteBuffer << uint16(profile->FrameHeight); + byteBuffer << uint16(profile->Unk152); + byteBuffer << uint8(profile->Unk147); + byteBuffer << uint16(profile->Unk150); + byteBuffer << uint8(profile->Unk146); + byteBuffer << uint8(profile->HealthText); + byteBuffer << uint8(profile->SortBy); + byteBuffer << uint16(profile->FrameWidth); + byteBuffer << uint8(profile->Unk148); + byteBuffer.WriteString(profile->ProfileName); + } + + data.FlushBits(); + data.append(byteBuffer); + SendPacket(&data); +} diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 6fedc481a14..dabe40e427e 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -30,6 +30,7 @@ #include "WaypointMovementGenerator.h" #include "InstanceSaveMgr.h" #include "ObjectMgr.h" +#include "MovementStructures.h" #include "Vehicle.h" #define MOVEMENT_PACKET_TIME_DELAY 0 @@ -195,16 +196,33 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->ProcessDelayedOperations(); } -void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData) +void WorldSession::HandleMoveTeleportAck(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "MSG_MOVE_TELEPORT_ACK"); - uint64 guid; - - recvData.readPackGUID(guid); + ObjectGuid guid; uint32 flags, time; - recvData >> flags >> time; - TC_LOG_DEBUG("network", "Guid " UI64FMTD, guid); + recvPacket >> flags >> time; + + guid[5] = recvPacket.ReadBit(); + guid[0] = recvPacket.ReadBit(); + guid[1] = recvPacket.ReadBit(); + guid[6] = recvPacket.ReadBit(); + guid[3] = recvPacket.ReadBit(); + guid[7] = recvPacket.ReadBit(); + guid[2] = recvPacket.ReadBit(); + guid[4] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guid[4]); + recvPacket.ReadByteSeq(guid[2]); + recvPacket.ReadByteSeq(guid[7]); + recvPacket.ReadByteSeq(guid[6]); + recvPacket.ReadByteSeq(guid[5]); + recvPacket.ReadByteSeq(guid[1]); + recvPacket.ReadByteSeq(guid[3]); + recvPacket.ReadByteSeq(guid[0]); + + TC_LOG_DEBUG("network", "Guid " UI64FMTD, uint64(guid)); TC_LOG_DEBUG("network", "Flags %u, time %u", flags, time/IN_MILLISECONDS); Player* plMover = _player->m_mover->ToPlayer(); @@ -246,9 +264,9 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData) GetPlayer()->ProcessDelayedOperations(); } -void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) +void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket) { - uint16 opcode = recvData.GetOpcode(); + uint16 opcode = recvPacket.GetOpcode(); Unit* mover = _player->m_mover; @@ -259,46 +277,41 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plrMover && plrMover->IsBeingTeleported()) { - recvData.rfinish(); // prevent warnings spam + recvPacket.rfinish(); // prevent warnings spam return; } /* extract packet */ - uint64 guid; - - recvData.readPackGUID(guid); - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recvData, &movementInfo); - - recvData.rfinish(); // prevent warnings spam + GetPlayer()->ReadMovementInfo(recvPacket, &movementInfo); // prevent tampered movement data - if (guid != mover->GetGUID()) + if (movementInfo.guid != mover->GetGUID()) + { + TC_LOG_ERROR("network", "HandleMovementOpcodes: guid error"); return; - + } if (!movementInfo.pos.IsPositionValid()) { - recvData.rfinish(); // prevent warnings spam + TC_LOG_ERROR("network", "HandleMovementOpcodes: Invalid Position"); return; } /* handle special cases */ - if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) + if (movementInfo.transport.guid) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.transport.pos.GetPositionX() > 50 || movementInfo.transport.pos.GetPositionY() > 50 || movementInfo.transport.pos.GetPositionZ() > 50) { - recvData.rfinish(); // prevent warnings spam + recvPacket.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation())) { - recvData.rfinish(); // prevent warnings spam + recvPacket.rfinish(); // prevent warnings spam return; } @@ -316,7 +329,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) transport->AddPassenger(plrMover); else - movementInfo.transport.Reset(); + movementInfo.ResetTransport(); } } @@ -324,14 +337,11 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) - movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + movementInfo.transport.guid = 0; } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave - { - plrMover->GetTransport()->RemovePassenger(plrMover); - movementInfo.transport.Reset(); - } + plrMover->m_transport->RemovePassenger(plrMover); // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight()) @@ -349,13 +359,9 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) m_clientTimeDelay = mstime - movementInfo.time; /* process position-change */ - WorldPacket data(opcode, recvData.size()); movementInfo.time = movementInfo.time + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; movementInfo.guid = mover->GetGUID(); - WriteMovementInfo(&data, &movementInfo); - mover->SendMessageToSet(&data, _player); - mover->m_movementInfo = movementInfo; // Some vehicles allow the passenger to turn by himself @@ -377,6 +383,10 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) mover->UpdatePosition(movementInfo.pos); + WorldPacket data(SMSG_PLAYER_MOVE, recvPacket.size()); + mover->WriteMovementInfo(data); + mover->SendMessageToSet(&data, _player); + if (plrMover) // nothing is charmed, or player charmed { if (plrMover->IsSitState() && (movementInfo.flags & (MOVEMENTFLAG_MASK_MOVING | MOVEMENTFLAG_MASK_TURNING))) @@ -384,7 +394,9 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); - if (movementInfo.pos.GetPositionZ() < -500.0f) + AreaTableEntry const* zone = GetAreaEntryByAreaID(plrMover->GetAreaId()); + float depth = zone ? zone->MaxDepth : -500.0f; + if (movementInfo.pos.GetPositionZ() < depth) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { @@ -408,62 +420,62 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recvData) { uint32 opcode = recvData.GetOpcode(); - TC_LOG_DEBUG("network", "WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); /* extract packet */ - uint64 guid; - uint32 unk1; - float newspeed; - - recvData.readPackGUID(guid); + MovementInfo movementInfo; + static MovementStatusElements const speedElement = MSEExtraFloat; + Movement::ExtraMovementStatusElement extras(&speedElement); + GetPlayer()->ReadMovementInfo(recvData, &movementInfo, &extras); // now can skip not our packet - if (_player->GetGUID() != guid) + if (_player->GetGUID() != movementInfo.guid) { recvData.rfinish(); // prevent warnings spam return; } - // continue parse packet - - recvData >> unk1; // counter or moveEvent - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recvData, &movementInfo); - - recvData >> newspeed; + float newspeed = extras.Data.floatData; /*----------------*/ // client ACK send one packet for mounted/run case and need skip all except last from its // in other cases anti-cheat check can be fail in false case UnitMoveType move_type; - UnitMoveType force_move_type; - static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; + static char const* const move_type_name[MAX_MOVE_TYPE] = + { + "Walk", + "Run", + "RunBack", + "Swim", + "SwimBack", + "TurnRate", + "Flight", + "FlightBack", + "PitchRate" + }; switch (opcode) { - case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; - case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break; - case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break; - case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break; - case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break; - case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break; - case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break; - case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break; - case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break; + case CMSG_MOVE_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; break; + case CMSG_MOVE_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; break; + case CMSG_MOVE_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; break; + case CMSG_MOVE_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; break; + case CMSG_MOVE_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; break; + case CMSG_MOVE_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; break; + case CMSG_MOVE_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; break; + case CMSG_MOVE_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; break; + case CMSG_MOVE_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; break; default: TC_LOG_ERROR("network", "WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode); return; } // skip all forced speed changes except last and unexpected - // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. - if (_player->m_forced_speed_changes[force_move_type] > 0) + // in run/mounted case used one ACK and it must be skipped. m_forced_speed_changes[MOVE_RUN] store both. + if (_player->m_forced_speed_changes[move_type] > 0) { - --_player->m_forced_speed_changes[force_move_type]; - if (_player->m_forced_speed_changes[force_move_type] > 0) + --_player->m_forced_speed_changes[move_type]; + if (_player->m_forced_speed_changes[move_type] > 0) return; } @@ -484,17 +496,34 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recvData) } } -void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recvData) +void WorldSession::HandleSetActiveMoverOpcode(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_SET_ACTIVE_MOVER"); - uint64 guid; - recvData >> guid; + ObjectGuid guid; + + guid[7] = recvPacket.ReadBit(); + guid[2] = recvPacket.ReadBit(); + guid[1] = recvPacket.ReadBit(); + guid[0] = recvPacket.ReadBit(); + guid[4] = recvPacket.ReadBit(); + guid[5] = recvPacket.ReadBit(); + guid[6] = recvPacket.ReadBit(); + guid[3] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guid[3]); + recvPacket.ReadByteSeq(guid[2]); + recvPacket.ReadByteSeq(guid[4]); + recvPacket.ReadByteSeq(guid[0]); + recvPacket.ReadByteSeq(guid[5]); + recvPacket.ReadByteSeq(guid[1]); + recvPacket.ReadByteSeq(guid[6]); + recvPacket.ReadByteSeq(guid[7]); if (GetPlayer()->IsInWorld()) { if (_player->m_mover->GetGUID() != guid) - TC_LOG_DEBUG("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " (%s - Entry: %u) and should be " UI64FMTD, guid, GetLogNameForGuid(guid), GUID_ENPART(guid), _player->m_mover->GetGUID()); + TC_LOG_DEBUG("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " (%s - Entry: %u) and should be " UI64FMTD, uint64(guid), GetLogNameForGuid(guid), GUID_ENPART(guid), _player->m_mover->GetGUID()); } } @@ -502,14 +531,8 @@ void WorldSession::HandleMoveNotActiveMover(WorldPacket &recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); - uint64 old_mover_guid; - recvData.readPackGUID(old_mover_guid); - MovementInfo mi; - ReadMovementInfo(recvData, &mi); - - mi.guid = old_mover_guid; - + GetPlayer()->ReadMovementInfo(recvData, &mi); _player->m_movementInfo = mi; } @@ -525,29 +548,16 @@ void WorldSession::HandleMoveKnockBackAck(WorldPacket& recvData) { TC_LOG_DEBUG("network", "CMSG_MOVE_KNOCK_BACK_ACK"); - uint64 guid; - recvData.readPackGUID(guid); + MovementInfo movementInfo; + GetPlayer()->ReadMovementInfo(recvData, &movementInfo); - if (_player->m_mover->GetGUID() != guid) + if (_player->m_mover->GetGUID() != movementInfo.guid) return; - recvData.read_skip<uint32>(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recvData, &movementInfo); - _player->m_movementInfo = movementInfo; - WorldPacket data(MSG_MOVE_KNOCK_BACK, 66); - data.appendPackGUID(guid); - _player->BuildMovementPacket(&data); - - // knockback specific info - data << movementInfo.jump.sinAngle; - data << movementInfo.jump.cosAngle; - data << movementInfo.jump.xyspeed; - data << movementInfo.jump.zspeed; - + WorldPacket data(SMSG_MOVE_UPDATE_KNOCK_BACK, 66); + _player->WriteMovementInfo(data); _player->SendMessageToSet(&data, false); } @@ -561,7 +571,7 @@ void WorldSession::HandleMoveHoverAck(WorldPacket& recvData) recvData.read_skip<uint32>(); // unk MovementInfo movementInfo; - ReadMovementInfo(recvData, &movementInfo); + GetPlayer()->ReadMovementInfo(recvData, &movementInfo); recvData.read_skip<uint32>(); // unk2 } @@ -576,7 +586,7 @@ void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recvData) recvData.read_skip<uint32>(); // unk MovementInfo movementInfo; - ReadMovementInfo(recvData, &movementInfo); + GetPlayer()->ReadMovementInfo(recvData, &movementInfo); recvData.read_skip<uint32>(); // unk2 } @@ -586,10 +596,20 @@ void WorldSession::HandleSummonResponseOpcode(WorldPacket& recvData) if (!_player->IsAlive() || _player->IsInCombat()) return; - uint64 summoner_guid; + uint64 summonerGuid; bool agree; - recvData >> summoner_guid; + recvData >> summonerGuid; recvData >> agree; _player->SummonIfPossible(agree); } + +void WorldSession::HandleSetCollisionHeightAck(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "CMSG_MOVE_SET_COLLISION_HEIGHT_ACK"); + + static MovementStatusElements const heightElement = MSEExtraFloat; + Movement::ExtraMovementStatusElement extra(&heightElement); + MovementInfo movementInfo; + GetPlayer()->ReadMovementInfo(recvPacket, &movementInfo, &extra); +} diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 1311cda1ef9..02651a1af09 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -41,11 +41,12 @@ enum StableResultCode { STABLE_ERR_MONEY = 0x01, // "you don't have enough money" - STABLE_ERR_STABLE = 0x06, // currently used in most fail cases + STABLE_ERR_INVALID_SLOT = 0x03, // "That slot is locked" STABLE_SUCCESS_STABLE = 0x08, // stable success STABLE_SUCCESS_UNSTABLE = 0x09, // unstable/swap success STABLE_SUCCESS_BUY_SLOT = 0x0A, // buy slot success - STABLE_ERR_EXOTIC = 0x0C // "you are unable to control exotic creatures" + STABLE_ERR_EXOTIC = 0x0B, // "you are unable to control exotic creatures" + STABLE_ERR_STABLE = 0x0C, // "Internal pet error" }; void WorldSession::HandleTabardVendorActivateOpcode(WorldPacket& recvData) @@ -104,13 +105,6 @@ void WorldSession::SendShowBank(uint64 guid) SendPacket(&data); } -void WorldSession::SendShowMailBox(uint64 guid) -{ - WorldPacket data(SMSG_SHOW_MAILBOX, 8); - data << guid; - SendPacket(&data); -} - void WorldSession::HandleTrainerListOpcode(WorldPacket& recvData) { uint64 guid; @@ -159,6 +153,7 @@ void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) WorldPacket data(SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); data << guid; data << uint32(trainer_spells->trainerType); + data << uint32(1); // different value for each trainer, also found in CMSG_TRAINER_BUY_SPELL size_t count_pos = data.wpos(); data << uint32(trainer_spells->spellList.size()); @@ -196,9 +191,6 @@ void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state); data << uint32(floor(tSpell->spellCost * fDiscountMod)); - data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); - // primary prof. learn confirmation dialog - data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state data << uint8(tSpell->reqLevel); data << uint32(tSpell->reqSkill); data << uint32(tSpell->reqSkillValue); @@ -213,7 +205,7 @@ void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) data << uint32(prevSpellId); ++maxReq; } - if (maxReq == 3) + if (maxReq == 2) break; SpellsRequiringSpellMapBounds spellsRequired = sSpellMgr->GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]); for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2) @@ -221,15 +213,19 @@ void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) data << uint32(itr2->second); ++maxReq; } - if (maxReq == 3) + if (maxReq == 2) break; } - while (maxReq < 3) + while (maxReq < 2) { data << uint32(0); ++maxReq; } + data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); + // primary prof. learn confirmation dialog + data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state + ++count; } @@ -242,9 +238,10 @@ void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) { uint64 guid; - uint32 spellId = 0; + uint32 spellId; + uint32 trainerId; - recvData >> guid >> spellId; + recvData >> guid >> trainerId >> spellId; TC_LOG_DEBUG("network", "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u", uint32(GUID_LOPART(guid)), spellId); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); @@ -261,28 +258,40 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) // check present spell in trainer spell list TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); if (!trainer_spells) + { + SendTrainerBuyFailed(guid, spellId, 0); return; + } // not found, cheat? TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); if (!trainer_spell) + { + SendTrainerBuyFailed(guid, spellId, 0); return; + } // can't be learn, cheat? Or double learn with lags... if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) + { + SendTrainerBuyFailed(guid, spellId, 0); return; + } // apply reputation discount uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); // check money requirement - if (!_player->HasEnoughMoney(nSpellCost)) + if (!_player->HasEnoughMoney(uint64(nSpellCost))) + { + SendTrainerBuyFailed(guid, spellId, 1); return; + } - _player->ModifyMoney(-int32(nSpellCost)); + _player->ModifyMoney(-int64(nSpellCost)); - unit->SendPlaySpellVisual(179); // 53 SpellCastDirected - unit->SendPlaySpellImpact(_player->GetGUID(), 362); // 113 EmoteSalute + unit->SendPlaySpellVisualKit(179, 0); // 53 SpellCastDirected + _player->SendPlaySpellVisualKit(362, 1); // 113 EmoteSalute // learn explicitly or cast explicitly if (trainer_spell->IsCastable()) @@ -292,7 +301,16 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, 12); data << uint64(guid); - data << uint32(spellId); // should be same as in packet from client + data << uint32(spellId); + SendPacket(&data); +} + +void WorldSession::SendTrainerBuyFailed(uint64 guid, uint32 spellId, uint32 reason) +{ + WorldPacket data(SMSG_TRAINER_BUY_FAILED, 16); + data << uint64(guid); + data << uint32(spellId); // should be same as in packet from client + data << uint32(reason); // 1 == "Not enough money for trainer service." 0 == "Trainer service %d unavailable." SendPacket(&data); } @@ -320,9 +338,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData) // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); if (unit->IsArmorer() || unit->IsCivilian() || unit->IsQuestGiver() || unit->IsServiceProvider() || unit->IsGuard()) - { unit->StopMoving(); - } // If spiritguide, no need for gossip menu, just put player into resurrect queue if (unit->IsSpiritGuide()) @@ -472,7 +488,7 @@ void WorldSession::SendBindPoint(Creature* npc) // send spell for homebinding (3286) npc->CastSpell(_player, bindspell, true); - WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, (8+4)); + WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, 12); data << uint64(npc->GetGUID()); data << uint32(bindspell); SendPacket(&data); @@ -536,6 +552,7 @@ void WorldSession::SendStablePetCallback(PreparedQueryResult result, uint64 guid // not let move dead pet in slot if (pet && pet->IsAlive() && pet->getPetType() == HUNTER_PET) { + data << uint32(num); // 4.x unknown, some kind of order? data << uint32(pet->GetCharmInfo()->GetPetNumber()); data << uint32(pet->GetEntry()); data << uint32(pet->getLevel()); @@ -550,6 +567,7 @@ void WorldSession::SendStablePetCallback(PreparedQueryResult result, uint64 guid { Field* fields = result->Fetch(); + data << uint32(num); data << uint32(fields[1].GetUInt32()); // petnumber data << uint32(fields[2].GetUInt32()); // creature entry data << uint32(fields[3].GetUInt16()); // level @@ -638,14 +656,13 @@ void WorldSession::HandleStablePetCallback(PreparedQueryResult result) while (result->NextRow()); } - WorldPacket data(SMSG_STABLE_RESULT, 1); if (freeSlot > 0 && freeSlot <= GetPlayer()->m_stableSlots) { _player->RemovePet(_player->GetPet(), PetSaveMode(freeSlot)); SendStableResult(STABLE_SUCCESS_STABLE); } else - SendStableResult(STABLE_ERR_STABLE); + SendStableResult(STABLE_ERR_INVALID_SLOT); } void WorldSession::HandleUnstablePet(WorldPacket& recvData) @@ -748,7 +765,7 @@ void WorldSession::HandleBuyStableSlot(WorldPacket& recvData) if (GetPlayer()->m_stableSlots < MAX_PET_STABLES) { - StableSlotPricesEntry const* SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); + /*StableSlotPricesEntry const* SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); if (_player->HasEnoughMoney(SlotPrice->Price)) { ++GetPlayer()->m_stableSlots; @@ -756,7 +773,7 @@ void WorldSession::HandleBuyStableSlot(WorldPacket& recvData) SendStableResult(STABLE_SUCCESS_BUY_SLOT); } else - SendStableResult(STABLE_ERR_MONEY); + SendStableResult(STABLE_ERR_MONEY);*/ } else SendStableResult(STABLE_ERR_STABLE); @@ -827,13 +844,15 @@ void WorldSession::HandleStableSwapPetCallback(PreparedQueryResult result, uint3 } CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry); - if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets())) + if (!creatureInfo || !creatureInfo->IsTameable(true)) { - // if problem in exotic pet - if (creatureInfo && creatureInfo->IsTameable(true)) - SendStableResult(STABLE_ERR_EXOTIC); - else - SendStableResult(STABLE_ERR_STABLE); + SendStableResult(STABLE_ERR_STABLE); + return; + } + + if (!creatureInfo->IsTameable(_player->CanTameExoticPets())) + { + SendStableResult(STABLE_ERR_EXOTIC); return; } diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 9346e982bd2..f3dc24a8c01 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -61,9 +61,14 @@ void WorldSession::HandlePetAction(WorldPacket& recvData) uint64 guid1; uint32 data; uint64 guid2; + float x, y, z; recvData >> guid1; //pet guid recvData >> data; recvData >> guid2; //tag guid + // Position + recvData >> x; + recvData >> y; + recvData >> z; uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1 @@ -98,7 +103,7 @@ void WorldSession::HandlePetAction(WorldPacket& recvData) return; if (GetPlayer()->m_Controlled.size() == 1) - HandlePetActionHelper(pet, guid1, spellid, flag, guid2); + HandlePetActionHelper(pet, guid1, spellid, flag, guid2, x, y, z); else { //If a pet is dismissed, m_Controlled will change @@ -107,7 +112,7 @@ void WorldSession::HandlePetAction(WorldPacket& recvData) if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->IsAlive()) controlled.push_back(*itr); for (std::vector<Unit*>::iterator itr = controlled.begin(); itr != controlled.end(); ++itr) - HandlePetActionHelper(*itr, guid1, spellid, flag, guid2); + HandlePetActionHelper(*itr, guid1, spellid, flag, guid2, x, y, z); } } @@ -139,7 +144,7 @@ void WorldSession::HandlePetStopAttack(WorldPacket &recvData) pet->AttackStop(); } -void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid, uint16 flag, uint64 guid2) +void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid, uint16 flag, uint64 guid2, float x, float y, float z) { CharmInfo* charmInfo = pet->GetCharmInfo(); if (!charmInfo) @@ -261,6 +266,18 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid } } break; + case COMMAND_MOVE_TO: + pet->StopMoving(); + pet->GetMotionMaster()->Clear(false); + pet->GetMotionMaster()->MovePoint(0, x, y, z); + charmInfo->SetCommandState(COMMAND_MOVE_TO); + + charmInfo->SetIsCommandAttack(false); + charmInfo->SetIsAtStay(true); + charmInfo->SetIsFollowing(false); + charmInfo->SetIsReturning(false); + charmInfo->SaveStayPosition(); + break; default: TC_LOG_ERROR("network", "WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); } @@ -680,15 +697,7 @@ void WorldSession::HandlePetAbandon(WorldPacket& recvData) if (pet) { if (pet->IsPet()) - { - if (pet->GetGUID() == _player->GetPetGUID()) - { - uint32 feelty = pet->GetPower(POWER_HAPPINESS); - pet->SetPower(POWER_HAPPINESS, feelty > 50000 ? (feelty-50000) : 0); - } - _player->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED); - } else if (pet->GetGUID() == _player->GetCharmGUID()) _player->StopCastingCharm(); } @@ -833,14 +842,11 @@ void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, Dec WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1); data << uint32(error); data << name; + data << uint8(declinedName ? 1 : 0); if (declinedName) - { - data << uint8(1); for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) data << declinedName->name[i]; - } - else - data << uint8(0); + SendPacket(&data); } @@ -868,8 +874,8 @@ void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket& recvData) uint32 talentId, talentRank; - // Client has max 24 talents, rounded up : 30 - uint32 const MaxTalentsCount = 30; + // Client has max 19 talents, rounded up : 25 + uint32 const MaxTalentsCount = 25; for (uint32 i = 0; i < talentsCount && i < MaxTalentsCount; ++i) { diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp index d02b8986e08..8eb699a978f 100644 --- a/src/server/game/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -182,7 +182,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData) return; } - if (!_player->HasEnoughMoney(cost)) + if (!_player->HasEnoughMoney(uint64(cost))) { //player hasn't got enough money _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, charterid, 0); return; @@ -382,7 +382,7 @@ void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) void WorldSession::HandlePetitionRenameOpcode(WorldPacket& recvData) { - TC_LOG_DEBUG("network", "Received opcode MSG_PETITION_RENAME"); // ok + TC_LOG_DEBUG("network", "Received opcode MSG_PETITION_RENAME"); uint64 petitionGuid; uint32 type; @@ -550,14 +550,10 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket& recvData) WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); data << uint64(petitionGuid); data << uint64(_player->GetGUID()); - data << (uint32)PETITION_SIGN_ALREADY_SIGNED; + data << uint32(PETITION_SIGN_ALREADY_SIGNED); // close at signer side SendPacket(&data); - - // update for owner if online - if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) - owner->GetSession()->SendPacket(&data); return; } @@ -779,7 +775,7 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket& recvData) if (_player->GetGuildId()) { data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); - data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; + data << uint32(PETITION_TURN_ALREADY_IN_GUILD); _player->GetSession()->SendPacket(&data); return; } diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index dbcfb1c4970..fb160c2bc41 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -96,57 +96,75 @@ void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recvData) uint64 guid; recvData >> guid; - CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(entry); - if (ci) + CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry); + if (creatureInfo) { + std::string Name, FemaleName, SubName; + Name = creatureInfo->Name; + FemaleName = creatureInfo->FemaleName; + SubName = creatureInfo->SubName; - std::string Name, SubName; - Name = ci->Name; - SubName = ci->SubName; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) + LocaleConstant locale = GetSessionDbLocaleIndex(); + if (locale >= 0) { - if (CreatureLocale const* cl = sObjectMgr->GetCreatureLocale(entry)) + if (CreatureLocale const* creatureLocale = sObjectMgr->GetCreatureLocale(entry)) { - ObjectMgr::GetLocaleString(cl->Name, loc_idx, Name); - ObjectMgr::GetLocaleString(cl->SubName, loc_idx, SubName); + ObjectMgr::GetLocaleString(creatureLocale->Name, locale, Name); + ObjectMgr::GetLocaleString(creatureLocale->FemaleName, locale, FemaleName); + ObjectMgr::GetLocaleString(creatureLocale->SubName, locale, SubName); } } - TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name.c_str(), entry); - // guess size - WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100); - data << uint32(entry); // creature entry - data << Name; - data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty - data << SubName; - data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0 - data << uint32(ci->type_flags); // flags - data << uint32(ci->type); // CreatureType.dbc - data << uint32(ci->family); // CreatureFamily.dbc - data << uint32(ci->rank); // Creature Rank (elite, boss, etc) - data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit - data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit - data << uint32(ci->Modelid1); // Modelid1 - data << uint32(ci->Modelid2); // Modelid2 - data << uint32(ci->Modelid3); // Modelid3 - data << uint32(ci->Modelid4); // Modelid4 - data << float(ci->ModHealth); // dmg/hp modifier - data << float(ci->ModMana); // dmg/mana modifier - data << uint8(ci->RacialLeader); - for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) - data << uint32(ci->questItems[i]); // itemId[6], quest drop - data << uint32(ci->movementId); // CreatureMovementInfo.dbc + + TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", creatureInfo->Name.c_str(), entry); + + WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100); // guess size + data << uint32(entry); // creature entry + data << Name; // Name + + for (uint8 i = 0; i < 3; i++) + data << uint8(0); // name2, ..., name3 + + data << FemaleName; // FemaleName + + for (uint8 i = 0; i < 3; i++) + data << uint8(0); // name5, ..., name8 + + data << SubName; // SubName + data << creatureInfo->IconName; // "Directions" for guard, string for Icons 2.3.0 + data << uint32(creatureInfo->type_flags); // flags + data << uint32(creatureInfo->type_flags2); // unknown meaning + data << uint32(creatureInfo->type); // CreatureType.dbc + data << uint32(creatureInfo->family); // CreatureFamily.dbc + data << uint32(creatureInfo->rank); // Creature Rank (elite, boss, etc) + data << uint32(creatureInfo->KillCredit[0]); // new in 3.1, kill credit + data << uint32(creatureInfo->KillCredit[1]); // new in 3.1, kill credit + data << uint32(creatureInfo->Modelid1); // Modelid1 + data << uint32(creatureInfo->Modelid2); // Modelid2 + data << uint32(creatureInfo->Modelid3); // Modelid3 + data << uint32(creatureInfo->Modelid4); // Modelid4 + data << float(creatureInfo->ModHealth); // dmg/hp modifier + data << float(creatureInfo->ModMana); // dmg/mana modifier + data << uint8(creatureInfo->RacialLeader); // RacialLeader + + for (uint8 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) + data << uint32(creatureInfo->questItems[i]); // itemId[6], quest drop + + data << uint32(creatureInfo->movementId); // CreatureMovementInfo.dbc + data << uint32(creatureInfo->expansionUnknown); // unknown meaning + SendPacket(&data); + TC_LOG_DEBUG("network", "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); } else { TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (GUID: %u, ENTRY: %u)", GUID_LOPART(guid), entry); + WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4); data << uint32(entry | 0x80000000); SendPacket(&data); + TC_LOG_DEBUG("network", "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); } } @@ -192,7 +210,8 @@ void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recvData) data.append(info->raw.data, MAX_GAMEOBJECT_DATA); data << float(info->size); // go size for (uint32 i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i) - data << uint32(info->questItems[i]); // itemId[6], quest drop + data << uint32(info->questItems[i]); // itemId[6], quest drop + data << int32(info->unkInt32); // 4.x, unknown SendPacket(&data); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); } @@ -207,7 +226,7 @@ void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recvData) } } -void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleCorpseQueryOpcode(WorldPacket& /*recvData*/) { TC_LOG_DEBUG("network", "WORLD: Received MSG_CORPSE_QUERY"); @@ -389,8 +408,8 @@ void WorldSession::HandleCorpseMapPositionQuery(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY"); - uint32 unk; - recvData >> unk; + uint32 transportGuidLow; + recvData >> transportGuidLow; WorldPacket data(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4+4+4+4); data << float(0); diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index d4dc7a9ab0d..a01cfa6d5e7 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -65,8 +65,8 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket& recvData) break; } - // inform client about status of quest - _player->PlayerTalkClass->SendQuestGiverStatus(uint8(questStatus), guid); + //inform client about status of quest + _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, guid); } void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket& recvData) @@ -267,36 +267,48 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData) TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %u, quest = %u, reward = %u", uint32(GUID_LOPART(guid)), questId, reward); - Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT); - if (!object || !object->hasInvolvedQuest(questId)) + Quest const* quest = sObjectMgr->GetQuestTemplate(questId); + if (!quest) return; - // some kind of WPE protection - if (!_player->CanInteractWithQuestGiver(object)) - return; + Object* object = _player; - if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) + if (!quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) { - if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE) || - (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete())) - { - TC_LOG_ERROR("network", "Error in QUEST_STATUS_COMPLETE: player %s (guid %u) tried to complete quest %u, but is not allowed to do so (possible packet-hacking or high latency)", - _player->GetName().c_str(), _player->GetGUIDLow(), questId); + object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + if (!object || !object->hasInvolvedQuest(questId)) return; - } - if (_player->CanRewardQuest(quest, reward, true)) - { - _player->RewardQuest(quest, reward, object); - switch (object->GetTypeId()) + // some kind of WPE protection + if (!_player->CanInteractWithQuestGiver(object)) + return; + } + + if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE) || + (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete())) + { + TC_LOG_ERROR("network", "Error in QUEST_STATUS_COMPLETE: player %s (guid %u) tried to complete quest %u, but is not allowed to do so (possible packet-hacking or high latency)", + _player->GetName().c_str(), _player->GetGUIDLow(), questId); + return; + } + + if (_player->CanRewardQuest(quest, reward, true)) + { + _player->RewardQuest(quest, reward, object); + + switch (object->GetTypeId()) + { + case TYPEID_UNIT: + case TYPEID_PLAYER: { - case TYPEID_UNIT: + //For AutoSubmition was added plr case there as it almost same exclute AI script cases. + Creature* creatureQGiver = object->ToCreature(); + if (!creatureQGiver || !(sScriptMgr->OnQuestReward(_player, creatureQGiver, quest, reward))) { - Creature* questgiver = object->ToCreature(); - if (!sScriptMgr->OnQuestReward(_player, questgiver, quest, reward)) + // Send next quest + if (Quest const* nextQuest = _player->GetNextQuest(guid, quest)) { - // Send next quest - if (Quest const* nextQuest = _player->GetNextQuest(guid, quest)) + if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true)) { if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true)) _player->AddQuestAndCheckCompletion(nextQuest, object); @@ -304,17 +316,23 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData) _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true); } - questgiver->AI()->sQuestReward(_player, quest, reward); + _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true); } - break; + + if (creatureQGiver) + creatureQGiver->AI()->sQuestReward(_player, quest, reward); } - case TYPEID_GAMEOBJECT: + break; + } + case TYPEID_GAMEOBJECT: + { + GameObject* questGiver = object->ToGameObject(); + if (!sScriptMgr->OnQuestReward(_player, questGiver, quest, reward)) { - GameObject* questGiver = object->ToGameObject(); - if (!sScriptMgr->OnQuestReward(_player, questGiver, quest, reward)) + // Send next quest + if (Quest const* nextQuest = _player->GetNextQuest(guid, quest)) { - // Send next quest - if (Quest const* nextQuest = _player->GetNextQuest(guid, quest)) + if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true)) { if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true)) _player->AddQuestAndCheckCompletion(nextQuest, object); @@ -322,17 +340,19 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData) _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true); } - questGiver->AI()->QuestReward(_player, quest, reward); + _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true); } - break; + + questGiver->AI()->QuestReward(_player, quest, reward); } - default: - break; + break; } + default: + break; } - else - _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true); } + else + _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true); } void WorldSession::HandleQuestgiverRequestRewardOpcode(WorldPacket& recvData) @@ -425,7 +445,7 @@ void WorldSession::HandleQuestConfirmAccept(WorldPacket& recvData) uint32 questId; recvData >> questId; - TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT quest = %u", questId); + TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT questId = %u", questId); if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) { @@ -449,28 +469,48 @@ void WorldSession::HandleQuestConfirmAccept(WorldPacket& recvData) void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recvData) { uint32 questId; - uint64 guid; - - recvData >> guid >> questId; + uint64 guid; // NPC / GameObject guid for normal quest completion. Player guid for self-completed quests + bool autoCompleteMode; // 0 - standart complete quest mode with npc, 1 - auto-complete mode + recvData >> guid >> questId >> autoCompleteMode; - TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, quest = %u", uint32(GUID_LOPART(guid)), questId); + TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, questId = %u self-complete: %u", uint32(GUID_LOPART(guid)), questId, autoCompleteMode ? 1 : 0); Quest const* quest = sObjectMgr->GetQuestTemplate(questId); if (!quest) return; - Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT); - if (!object || !object->hasInvolvedQuest(questId)) + if (autoCompleteMode && !quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) return; - // some kind of WPE protection - if (!_player->CanInteractWithQuestGiver(object)) + Object* object = nullptr; + if (autoCompleteMode) + object = _player; + else + object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT); + + if (!object) return; + if (autoCompleteMode == 0) + { + if (!object->hasInvolvedQuest(questId)) + return; + + // some kind of WPE protection + if (!_player->CanInteractWithQuestGiver(object)) + return; + } + else + { + // Do not allow completing quests on other players. + if (guid != _player->GetGUID()) + return; + } + if (!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE) { TC_LOG_ERROR("network", "Possible hacking attempt: Player %s [guid: %u] tried to complete quest [entry: %u] without being in possession of the quest!", - _player->GetName().c_str(), _player->GetGUIDLow(), questId); + _player->GetName().c_str(), _player->GetGUIDLow(), questId); return; } @@ -563,7 +603,7 @@ void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket) if (quest->IsAutoAccept() && receiver->CanAddQuest(quest, true) && receiver->CanTakeQuest(quest, true)) receiver->AddQuestAndCheckCompletion(quest, sender); - if ((quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) || quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) + if (quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) receiver->PlayerTalkClass->SendQuestGiverRequestItems(quest, sender->GetGUID(), receiver->CanCompleteRepeatableQuest(quest), true); else { @@ -602,7 +642,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket uint32 count = 0; - WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4); + WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4 + 8 + 4); data << uint32(count); // placeholder for (Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) @@ -621,7 +661,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket questStatus = _player->GetQuestDialogStatus(questgiver); data << uint64(questgiver->GetGUID()); - data << uint8(questStatus); + data << uint32(questStatus); ++count; } else if (IS_GAMEOBJECT_GUID(*itr)) @@ -633,7 +673,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket questStatus = _player->GetQuestDialogStatus(questgiver); data << uint64(questgiver->GetGUID()); - data << uint8(questStatus); + data << uint32(questStatus); ++count; } } @@ -642,7 +682,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket SendPacket(&data); } -void WorldSession::HandleQueryQuestsCompleted(WorldPacket & /*recvData*/) +void WorldSession::HandleQueryQuestsCompleted(WorldPacket& /*recvData*/) { size_t rew_count = _player->GetRewardedQuestCount(); diff --git a/src/server/game/Handlers/ReferAFriendHandler.cpp b/src/server/game/Handlers/ReferAFriendHandler.cpp index 3b348b6e214..2efc9df5d94 100644 --- a/src/server/game/Handlers/ReferAFriendHandler.cpp +++ b/src/server/game/Handlers/ReferAFriendHandler.cpp @@ -48,7 +48,8 @@ void WorldSession::HandleGrantLevel(WorldPacket& recvData) else if (target->GetGroup() != _player->GetGroup()) error = ERR_REFER_A_FRIEND_NOT_IN_GROUP; - if (error) { + if (error) + { WorldPacket data(SMSG_REFER_A_FRIEND_FAILURE, 24); data << uint32(error); if (error == ERR_REFER_A_FRIEND_NOT_IN_GROUP) diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp index 92c7c60bca0..8e10fc94ea6 100644 --- a/src/server/game/Handlers/SkillHandler.cpp +++ b/src/server/game/Handlers/SkillHandler.cpp @@ -29,30 +29,50 @@ void WorldSession::HandleLearnTalentOpcode(WorldPacket& recvData) { - uint32 talent_id, requested_rank; - recvData >> talent_id >> requested_rank; + uint32 talentId, requestedRank; + recvData >> talentId >> requestedRank; - _player->LearnTalent(talent_id, requested_rank); - _player->SendTalentsInfoData(false); + if (_player->LearnTalent(talentId, requestedRank)) + _player->SendTalentsInfoData(false); } void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "CMSG_LEARN_PREVIEW_TALENTS"); + int32 tabPage; uint32 talentsCount; + recvPacket >> tabPage; // talent tree + + // prevent cheating (selecting new tree with points already in another) + if (tabPage >= 0) // -1 if player already has specialization + { + if (TalentTabEntry const* talentTabEntry = sTalentTabStore.LookupEntry(_player->GetPrimaryTalentTree(_player->GetActiveSpec()))) + { + if (talentTabEntry->tabpage != uint32(tabPage)) + { + recvPacket.rfinish(); + return; + } + } + } + recvPacket >> talentsCount; uint32 talentId, talentRank; - // Client has max 44 talents for tree for 3 trees, rounded up : 150 - uint32 const MaxTalentsCount = 150; + // Client has max 21 talents for tree for 3 trees, rounded up : 70 + uint32 const MaxTalentsCount = 70; for (uint32 i = 0; i < talentsCount && i < MaxTalentsCount; ++i) { recvPacket >> talentId >> talentRank; - _player->LearnTalent(talentId, talentRank); + if (!_player->LearnTalent(talentId, talentRank)) + { + recvPacket.rfinish(); + break; + } } _player->SendTalentsInfoData(false); @@ -80,7 +100,7 @@ void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recvData) if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - if (!(_player->ResetTalents())) + if (!_player->ResetTalents()) { WorldPacket data(MSG_TALENT_WIPE_CONFIRM, 8+4); //you have not any talent data << uint64(0); diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index ba30803e8c2..04e64634d88 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -21,6 +21,7 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "ObjectMgr.h" +#include "GuildMgr.h" #include "SpellMgr.h" #include "Log.h" #include "Opcodes.h" @@ -50,9 +51,27 @@ void WorldSession::HandleClientCastFlags(WorldPacket& recvPacket, uint8 castFlag uint8 hasMovementData; recvPacket >> hasMovementData; if (hasMovementData) - { - recvPacket.SetOpcode(recvPacket.read<uint32>()); HandleMovementOpcodes(recvPacket); + } + else if (castFlags & 0x8) // Archaeology + { + uint32 count, entry, usedCount; + uint8 type; + recvPacket >> count; + for (uint32 i = 0; i < count; ++i) + { + recvPacket >> type; + switch (type) + { + case 2: // Keystones + recvPacket >> entry; // Item id + recvPacket >> usedCount; // Item count + break; + case 1: // Fragments + recvPacket >> entry; // Currency id + recvPacket >> usedCount; // Currency count + break; + } } } } @@ -200,7 +219,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) // Verify that the bag is an actual bag or wrapped item that can be used "normally" if (!(proto->Flags & ITEM_PROTO_FLAG_OPENABLE) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { - pUser->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, item, NULL); + pUser->SendEquipError(EQUIP_ERR_CLIENT_LOCKED_OUT, item, NULL); TC_LOG_ERROR("network", "Possible hacking attempt: Player %s [guid: %u] tried to open item [guid: %u, entry: %u] which is not openable!", pUser->GetName().c_str(), pUser->GetGUIDLow(), item->GetGUIDLow(), proto->ItemId); return; @@ -310,9 +329,13 @@ void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) { - uint32 spellId; + uint32 spellId, glyphIndex; uint8 castCount, castFlags; - recvPacket >> castCount >> spellId >> castFlags; + + recvPacket >> castCount; + recvPacket >> spellId; + recvPacket >> glyphIndex; + recvPacket >> castFlags; TC_LOG_DEBUG("network", "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u, data length = %u", castCount, spellId, castFlags, (uint32)recvPacket.size()); @@ -359,6 +382,27 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) return; } + Unit::AuraEffectList swaps = mover->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS); + Unit::AuraEffectList const& swaps2 = mover->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2); + if (!swaps2.empty()) + swaps.insert(swaps.end(), swaps2.begin(), swaps2.end()); + + if (!swaps.empty()) + { + for (Unit::AuraEffectList::const_iterator itr = swaps.begin(); itr != swaps.end(); ++itr) + { + if ((*itr)->IsAffectingSpell(spellInfo)) + { + if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo((*itr)->GetAmount())) + { + spellInfo = newInfo; + spellId = newInfo->Id; + } + break; + } + } + } + // Client is resending autoshot cast opcode when other spell is cast during shoot rotation // Skip it to prevent "interrupt" message if (spellInfo->IsAutoRepeatRangedSpell() && caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) @@ -392,6 +436,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, 0, false); spell->m_cast_count = castCount; // set count of casts + spell->m_glyphIndex = glyphIndex; spell->prepare(&targets); } @@ -506,8 +551,9 @@ void WorldSession::HandleTotemDestroyed(WorldPacket& recvPacket) return; uint8 slotId; - + uint64 guid; recvPacket >> slotId; + recvPacket >> guid; ++slotId; if (slotId >= MAX_TOTEM_SLOT) @@ -517,12 +563,11 @@ void WorldSession::HandleTotemDestroyed(WorldPacket& recvPacket) return; Creature* totem = GetPlayer()->GetMap()->GetCreature(_player->m_SummonSlot[slotId]); - - if (totem && totem->IsTotem()) + if (totem && totem->IsTotem() && totem->GetGUID() == guid) totem->ToTotem()->UnSummon(); } -void WorldSession::HandleSelfResOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleSelfResOpcode(WorldPacket& /*recvData*/) { TC_LOG_DEBUG("network", "WORLD: CMSG_SELF_RES"); // empty opcode @@ -562,6 +607,7 @@ void WorldSession::HandleMirrorImageDataRequest(WorldPacket& recvData) TC_LOG_DEBUG("network", "WORLD: CMSG_GET_MIRRORIMAGE_DATA"); uint64 guid; recvData >> guid; + recvData.read_skip<uint32>(); // DisplayId ? // Get unit for which data is needed by client Unit* unit = ObjectAccessor::GetObjectInWorld(guid, (Unit*)NULL); @@ -586,12 +632,17 @@ void WorldSession::HandleMirrorImageDataRequest(WorldPacket& recvData) if (creator->GetTypeId() == TYPEID_PLAYER) { Player* player = creator->ToPlayer(); + Guild* guild = NULL; + + if (uint32 guildId = player->GetGuildId()) + guild = sGuildMgr->GetGuildById(guildId); + data << uint8(player->GetByteValue(PLAYER_BYTES, 0)); // skin data << uint8(player->GetByteValue(PLAYER_BYTES, 1)); // face data << uint8(player->GetByteValue(PLAYER_BYTES, 2)); // hair data << uint8(player->GetByteValue(PLAYER_BYTES, 3)); // haircolor data << uint8(player->GetByteValue(PLAYER_BYTES_2, 0)); // facialhair - data << uint32(player->GetGuildId()); // unk + data << uint64(guild ? guild->GetGUID() : 0); static EquipmentSlots const itemSlots[] = { @@ -680,3 +731,28 @@ void WorldSession::HandleUpdateProjectilePosition(WorldPacket& recvPacket) data << float(z); caster->SendMessageToSet(&data, true); } + +void WorldSession::HandleRequestCategoryCooldowns(WorldPacket& /*recvPacket*/) +{ + std::map<uint32, int32> categoryMods; + Unit::AuraEffectList const& categoryCooldownAuras = _player->GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN); + for (Unit::AuraEffectList::const_iterator itr = categoryCooldownAuras.begin(); itr != categoryCooldownAuras.end(); ++itr) + { + std::map<uint32, int32>::iterator cItr = categoryMods.find((*itr)->GetMiscValue()); + if (cItr == categoryMods.end()) + categoryMods[(*itr)->GetMiscValue()] = (*itr)->GetAmount(); + else + cItr->second += (*itr)->GetAmount(); + } + + WorldPacket data(SMSG_SPELL_CATEGORY_COOLDOWN, 11); + data.WriteBits(categoryMods.size(), 23); + data.FlushBits(); + for (std::map<uint32, int32>::const_iterator itr = categoryMods.begin(); itr != categoryMods.end(); ++itr) + { + data << uint32(itr->first); + data << int32(-itr->second); + } + + SendPacket(&data); +} diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index 34899fc23df..aaa9188b6f4 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -94,12 +94,12 @@ void WorldSession::SendTaxiMenu(Creature* unit) { // find current node uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); - - if (curloc == 0) + if (!curloc) return; bool lastTaxiCheaterState = GetPlayer()->isTaxiCheater(); - if (unit->GetEntry() == 29480) GetPlayer()->SetTaxiCheater(true); // Grimwing in Ebon Hold, special case. NOTE: Not perfect, Zul'Aman should not be included according to WoWhead, and I think taxicheat includes it. + if (unit->GetEntry() == 29480) + GetPlayer()->SetTaxiCheater(true); // Grimwing in Ebon Hold, special case. NOTE: Not perfect, Zul'Aman should not be included according to WoWhead, and I think taxicheat includes it. TC_LOG_DEBUG("network", "WORLD: CMSG_TAXINODE_STATUS_QUERY %u ", curloc); @@ -207,13 +207,10 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_MOVE_SPLINE_DONE"); - uint64 guid; // used only for proper packet read - recvData.readPackGUID(guid); + recvData.read_skip<uint32>(); // unk MovementInfo movementInfo; // used only for proper packet read - ReadMovementInfo(recvData, &movementInfo); - - recvData.read_skip<uint32>(); // unk + _player->ReadMovementInfo(recvData, &movementInfo); // in taxi flight packet received in 2 case: // 1) end taxi path in far (multi-node) flight diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp index a2aa426c096..53cde5e8e5a 100644 --- a/src/server/game/Handlers/TicketHandler.cpp +++ b/src/server/game/Handlers/TicketHandler.cpp @@ -44,7 +44,7 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket& recvData) GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID()); if (ticket && ticket->IsCompleted()) - sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID());; + sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID()); // Player must not have ticket if (!ticket || ticket->IsClosed()) @@ -190,7 +190,7 @@ void WorldSession::HandleGMSurveySubmit(WorldPacket& recvData) std::unordered_set<uint32> surveyIds; SQLTransaction trans = CharacterDatabase.BeginTransaction(); // sub_survey1, r1, comment1, sub_survey2, r2, comment2, sub_survey3, r3, comment3, sub_survey4, r4, comment4, sub_survey5, r5, comment5, sub_survey6, r6, comment6, sub_survey7, r7, comment7, sub_survey8, r8, comment8, sub_survey9, r9, comment9, sub_survey10, r10, comment10, - for (uint8 i = 0; i < 10; i++) + for (uint8 i = 0; i < 15; i++) { uint32 subSurveyId; // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc) recvData >> subSurveyId; diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 884c4a83b15..f6c403acb66 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -30,38 +30,47 @@ #include "Language.h" #include "AccountMgr.h" -void WorldSession::SendTradeStatus(TradeStatus status) +void WorldSession::SendTradeStatus(TradeStatus status, int8 clearSlot) { WorldPacket data; + Player* trader = GetPlayer()->GetTrader(); + + data.Initialize(SMSG_TRADE_STATUS, 1+4+4); + data.WriteBit(trader ? (trader->GetSession()->GetBattlenetAccountId() == GetBattlenetAccountId()) : 0); // IsSameBnetAccount, used for trading heirlooms and other battle.net bound items with your other accounts + data.WriteBits(status, 5); + switch (status) { case TRADE_STATUS_BEGIN_TRADE: - data.Initialize(SMSG_TRADE_STATUS, 4+8); - data << uint32(status); - data << uint64(0); + data.WriteBits(0, 8); // Trader Guid + data.FlushBits(); break; case TRADE_STATUS_OPEN_WINDOW: - data.Initialize(SMSG_TRADE_STATUS, 4+4); - data << uint32(status); - data << uint32(0); // added in 2.4.0 + data.FlushBits(); + data << uint32(0); // Trade Id break; case TRADE_STATUS_CLOSE_WINDOW: - data.Initialize(SMSG_TRADE_STATUS, 4+4+1+4); - data << uint32(status); - data << uint32(0); - data << uint8(0); - data << uint32(0); + data.WriteBit(0); // Error bool (0 = Target, 1 = Self) + data.FlushBits(); + data << uint32(0); // Error Item (Relevant item to the error) + data << uint32(0); // InventoryResult break; - case TRADE_STATUS_ONLY_CONJURED: + case TRADE_STATUS_ONLY_CONJURED: // Not Implemented case TRADE_STATUS_NOT_ELIGIBLE: - data.Initialize(SMSG_TRADE_STATUS, 4+1); - data << uint32(status); - data << uint8(0); + // Used when trading loot soulbound items with people that are not eligible (TRADE_STATUS_NOT_ELIGIBLE), + // and when trying to trade items with players in other realms when in a cross realm BG, you can only trade conjured goods with them (TRADE_STATUS_ONLY_CONJURED) + data.FlushBits(); + data << int8(clearSlot); // Trade slot to clear, -1 = Clear the money amount break; + case TRADE_STATUS_CURRENCY: // Not implemented + case TRADE_STATUS_CURRENCY_NOT_TRADABLE: // Not implemented + // Blizzard never implemented these, you can only trade currency with the field9 & 1 in CurrencyTypes.DBC, and only two test currencies have that flag + data.FlushBits(); + data << uint32(0); // Trading Currency Id + data << uint32(0); // Trading Currency Amount default: - data.Initialize(SMSG_TRADE_STATUS, 4); - data << uint32(status); + data.FlushBits(); break; } @@ -71,60 +80,117 @@ void WorldSession::SendTradeStatus(TradeStatus status) void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/) { TC_LOG_DEBUG("network", "WORLD: Ignore Trade %u", _player->GetGUIDLow()); - // recvPacket.print_storage(); } void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/) { TC_LOG_DEBUG("network", "WORLD: Busy Trade %u", _player->GetGUIDLow()); - // recvPacket.print_storage(); } void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) { TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); - WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4)); - data << uint8(trader_data); // 1 means traders data, 0 means own - data << uint32(0); // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) + ByteBuffer itemData(7*2 + 7*4 + 3*4 + 3*4 + 1); + + uint8 count = 0; + for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) + if (view_trade->GetItem(TradeSlots(i))) + ++count; + + WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 4*6 + 8 + 1 + 3 + count * 70); + data << uint32(0); // this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) + data << uint32(0); // unk 2 + data << uint64(view_trade->GetMoney()); // trader gold + data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases + data << uint32(0); // unk 5 + data << uint8(trader_data); // 1 means traders data, 0 means own data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases - data << uint32(view_trade->GetMoney()); // trader gold - data << uint32(view_trade->GetSpell()); // spell cast on lowest slot item + data.WriteBits(count, 22); for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) { - data << uint8(i); // trade slot number, if not specified, then end of packet + Item* item = view_trade->GetItem(TradeSlots(i)); + if (!item) + continue; - if (Item* item = view_trade->GetItem(TradeSlots(i))) - { - data << uint32(item->GetTemplate()->ItemId); // entry - data << uint32(item->GetTemplate()->DisplayInfoID);// display id - data << uint32(item->GetCount()); // stack count - // wrapped: hide stats but show giftcreator name - data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED) ? 1 : 0); - data << uint64(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)); - // perm. enchantment and gems - data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); - for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) - data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); - // creator - data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); - data << uint32(item->GetSpellCharges()); // charges - data << uint32(item->GetItemSuffixFactor()); // SuffixFactor - data << uint32(item->GetItemRandomPropertyId());// random properties id - data << uint32(item->GetTemplate()->LockID); // lock id - // max durability - data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); - // durability - data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); - } - else + ObjectGuid giftCreatorGuid = item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); + ObjectGuid creatorGuid = item->GetUInt64Value(ITEM_FIELD_CREATOR); + + data.WriteBit(giftCreatorGuid[7]); + data.WriteBit(giftCreatorGuid[1]); + bool notWrapped = data.WriteBit(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)); + data.WriteBit(giftCreatorGuid[3]); + + if (notWrapped) { - for (uint8 j = 0; j < 18; ++j) - data << uint32(0); + data.WriteBit(creatorGuid[7]); + data.WriteBit(creatorGuid[1]); + data.WriteBit(creatorGuid[4]); + data.WriteBit(creatorGuid[6]); + data.WriteBit(creatorGuid[2]); + data.WriteBit(creatorGuid[3]); + data.WriteBit(creatorGuid[5]); + data.WriteBit(item->GetTemplate()->LockID != 0); + data.WriteBit(creatorGuid[0]); + + itemData.WriteByteSeq(creatorGuid[1]); + + itemData << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); + for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS /*3*/; ++enchant_slot) + itemData << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); + itemData << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); + + itemData.WriteByteSeq(creatorGuid[6]); + itemData.WriteByteSeq(creatorGuid[2]); + itemData.WriteByteSeq(creatorGuid[7]); + itemData.WriteByteSeq(creatorGuid[4]); + + itemData << uint32(item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT)); + itemData << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); + itemData << uint32(item->GetItemRandomPropertyId()); + + itemData.WriteByteSeq(creatorGuid[3]); + + itemData << uint32(0); // unk7 + + itemData.WriteByteSeq(creatorGuid[0]); + + itemData << uint32(item->GetSpellCharges()); + itemData << uint32(item->GetItemSuffixFactor()); + + itemData.WriteByteSeq(creatorGuid[5]); } + + data.WriteBit(giftCreatorGuid[6]); + data.WriteBit(giftCreatorGuid[4]); + data.WriteBit(giftCreatorGuid[2]); + data.WriteBit(giftCreatorGuid[0]); + data.WriteBit(giftCreatorGuid[5]); + + itemData.WriteByteSeq(giftCreatorGuid[6]); + itemData.WriteByteSeq(giftCreatorGuid[1]); + itemData.WriteByteSeq(giftCreatorGuid[7]); + itemData.WriteByteSeq(giftCreatorGuid[4]); + + itemData << uint32(item->GetTemplate()->ItemId); + + itemData.WriteByteSeq(giftCreatorGuid[0]); + + itemData << uint32(item->GetCount()); + + itemData.WriteByteSeq(giftCreatorGuid[5]); + + itemData << uint8(i); + + itemData.WriteByteSeq(giftCreatorGuid[2]); + itemData.WriteByteSeq(giftCreatorGuid[3]); } + + data.FlushBits(); + data.append(itemData); + SendPacket(&data); } @@ -299,14 +365,14 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) return; } - if (_player->GetMoney() >= MAX_MONEY_AMOUNT - his_trade->GetMoney()) + if (_player->GetMoney() >= uint64(MAX_MONEY_AMOUNT) - his_trade->GetMoney()) { _player->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); my_trade->SetAccepted(false, true); return; } - if (trader->GetMoney() >= MAX_MONEY_AMOUNT - my_trade->GetMoney()) + if (trader->GetMoney() >= uint64(MAX_MONEY_AMOUNT) - my_trade->GetMoney()) { trader->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); his_trade->SetAccepted(false, true); @@ -484,7 +550,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) { if (my_trade->GetMoney() > 0) { - sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", + sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: " UI64FMTD ") to player: %s (Account: %u)", _player->GetName().c_str(), _player->GetSession()->GetAccountId(), my_trade->GetMoney(), trader->GetName().c_str(), trader->GetSession()->GetAccountId()); @@ -492,7 +558,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) if (his_trade->GetMoney() > 0) { - sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", + sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: " UI64FMTD ") to player: %s (Account: %u)", trader->GetName().c_str(), trader->GetSession()->GetAccountId(), his_trade->GetMoney(), _player->GetName().c_str(), _player->GetSession()->GetAccountId()); @@ -500,9 +566,9 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) } // update money - _player->ModifyMoney(-int32(my_trade->GetMoney())); + _player->ModifyMoney(-int64(my_trade->GetMoney())); _player->ModifyMoney(his_trade->GetMoney()); - trader->ModifyMoney(-int32(his_trade->GetMoney())); + trader->ModifyMoney(-int64(his_trade->GetMoney())); trader->ModifyMoney(my_trade->GetMoney()); if (my_spell) @@ -562,15 +628,32 @@ void WorldSession::SendCancelTrade() void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/) { - // sended also after LOGOUT COMPLETE + // sent also after LOGOUT COMPLETE if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT _player->TradeCancel(true); } void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { - uint64 ID; - recvPacket >> ID; + ObjectGuid guid; + + guid[0] = recvPacket.ReadBit(); + guid[3] = recvPacket.ReadBit(); + guid[5] = recvPacket.ReadBit(); + guid[1] = recvPacket.ReadBit(); + guid[4] = recvPacket.ReadBit(); + guid[6] = recvPacket.ReadBit(); + guid[7] = recvPacket.ReadBit(); + guid[2] = recvPacket.ReadBit(); + + recvPacket.ReadByteSeq(guid[7]); + recvPacket.ReadByteSeq(guid[4]); + recvPacket.ReadByteSeq(guid[3]); + recvPacket.ReadByteSeq(guid[5]); + recvPacket.ReadByteSeq(guid[1]); + recvPacket.ReadByteSeq(guid[2]); + recvPacket.ReadByteSeq(guid[6]); + recvPacket.ReadByteSeq(guid[0]); if (GetPlayer()->m_trade) return; @@ -605,7 +688,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) return; } - Player* pOther = ObjectAccessor::FindPlayer(ID); + Player* pOther = ObjectAccessor::FindPlayer(guid); if (!pOther) { @@ -671,15 +754,36 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) _player->m_trade = new TradeData(_player, pOther); pOther->m_trade = new TradeData(pOther, _player); - WorldPacket data(SMSG_TRADE_STATUS, 12); - data << uint32(TRADE_STATUS_BEGIN_TRADE); - data << uint64(_player->GetGUID()); + WorldPacket data(SMSG_TRADE_STATUS, 2+7); + data.WriteBit(0); // unk bit, usually 0 + data.WriteBits(TRADE_STATUS_BEGIN_TRADE, 5); + + ObjectGuid playerGuid = _player->GetGUID(); + // WTB StartBitStream... + data.WriteBit(playerGuid[2]); + data.WriteBit(playerGuid[4]); + data.WriteBit(playerGuid[6]); + data.WriteBit(playerGuid[0]); + data.WriteBit(playerGuid[1]); + data.WriteBit(playerGuid[3]); + data.WriteBit(playerGuid[7]); + data.WriteBit(playerGuid[5]); + + data.WriteByteSeq(playerGuid[4]); + data.WriteByteSeq(playerGuid[1]); + data.WriteByteSeq(playerGuid[2]); + data.WriteByteSeq(playerGuid[3]); + data.WriteByteSeq(playerGuid[0]); + data.WriteByteSeq(playerGuid[7]); + data.WriteByteSeq(playerGuid[6]); + data.WriteByteSeq(playerGuid[5]); + pOther->GetSession()->SendPacket(&data); } void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket) { - uint32 gold; + uint64 gold; recvPacket >> gold; TradeData* my_trade = _player->GetTradeData(); @@ -696,9 +800,9 @@ void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) uint8 bag; uint8 slot; + recvPacket >> slot; recvPacket >> tradeSlot; recvPacket >> bag; - recvPacket >> slot; TradeData* my_trade = _player->GetTradeData(); if (!my_trade) @@ -729,6 +833,13 @@ void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) return; } + if (item->IsBindedNotWith(GetPlayer()->GetTrader())) + { + // The item is BOP tradeable but the trader wasn't eligible to get it. + SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE, tradeSlot); + return; + } + my_trade->SetItem(TradeSlots(tradeSlot), item); } diff --git a/src/server/game/Handlers/VehicleHandler.cpp b/src/server/game/Handlers/VehicleHandler.cpp index b3fa240e2d2..e17b33c345b 100644 --- a/src/server/game/Handlers/VehicleHandler.cpp +++ b/src/server/game/Handlers/VehicleHandler.cpp @@ -22,6 +22,7 @@ #include "Player.h" #include "Log.h" #include "ObjectAccessor.h" +#include "MovementStructures.h" void WorldSession::HandleDismissControlledVehicle(WorldPacket &recvData) { @@ -35,20 +36,15 @@ void WorldSession::HandleDismissControlledVehicle(WorldPacket &recvData) return; } - uint64 guid; - - recvData.readPackGUID(guid); - MovementInfo mi; - mi.guid = guid; - ReadMovementInfo(recvData, &mi); + _player->ReadMovementInfo(recvData, &mi); _player->m_movementInfo = mi; _player->ExitVehicle(); } -void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recvData) +void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); @@ -78,20 +74,36 @@ void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recvData) break; case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: { - uint64 guid; // current vehicle guid - recvData.readPackGUID(guid); - + static MovementStatusElements const accessoryGuid[] = + { + MSEExtraInt8, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte7, + }; + + Movement::ExtraMovementStatusElement extra(accessoryGuid); MovementInfo movementInfo; - ReadMovementInfo(recvData, &movementInfo); + GetPlayer()->ReadMovementInfo(recvData, &movementInfo, &extra); vehicle_base->m_movementInfo = movementInfo; - uint64 accessory; // accessory guid - recvData.readPackGUID(accessory); - - int8 seatId; - recvData >> seatId; + uint64 accessory = extra.Data.guid; + int8 seatId = extra.Data.byteData; - if (vehicle_base->GetGUID() != guid) + if (vehicle_base->GetGUID() != movementInfo.guid) return; if (!accessory) @@ -125,7 +137,7 @@ void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recvData) } } -void WorldSession::HandleEnterPlayerVehicle(WorldPacket &data) +void WorldSession::HandleEnterPlayerVehicle(WorldPacket& data) { // Read guid uint64 guid; @@ -144,7 +156,7 @@ void WorldSession::HandleEnterPlayerVehicle(WorldPacket &data) } } -void WorldSession::HandleEjectPassenger(WorldPacket &data) +void WorldSession::HandleEjectPassenger(WorldPacket& data) { Vehicle* vehicle = _player->GetVehicleKit(); if (!vehicle) diff --git a/src/server/game/Handlers/VoiceChatHandler.cpp b/src/server/game/Handlers/VoiceChatHandler.cpp index af2d8e20757..fd5d3adad84 100644 --- a/src/server/game/Handlers/VoiceChatHandler.cpp +++ b/src/server/game/Handlers/VoiceChatHandler.cpp @@ -30,10 +30,12 @@ void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket& recvData) recvData.read_skip<uint8>(); } -void WorldSession::HandleChannelVoiceOnOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleChannelVoiceOnOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: CMSG_CHANNEL_VOICE_ON"); // Enable Voice button in channel context menu + recvData.ReadString(recvData.ReadBits(8)); + //channel->EnableVoice(recvData.GetOpcode() == CMSG_CHANNEL_VOICE_ON); } void WorldSession::HandleSetActiveVoiceChannel(WorldPacket& recvData) diff --git a/src/server/game/Handlers/VoidStorageHandler.cpp b/src/server/game/Handlers/VoidStorageHandler.cpp new file mode 100644 index 00000000000..cf117762801 --- /dev/null +++ b/src/server/game/Handlers/VoidStorageHandler.cpp @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" +#include <list> +#include <vector> +#include <utility> + +void WorldSession::SendVoidStorageTransferResult(VoidTransferError result) +{ + WorldPacket data(SMSG_VOID_TRANSFER_RESULT, 4); + data << uint32(result); + SendPacket(&data); +} + +void WorldSession::HandleVoidStorageUnlock(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_VOID_STORAGE_UNLOCK"); + Player* player = GetPlayer(); + + ObjectGuid npcGuid; + npcGuid[4] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + npcGuid[2] = recvData.ReadBit(); + npcGuid[1] = recvData.ReadBit(); + npcGuid[7] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(npcGuid[2]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(npcGuid[0]); + recvData.ReadByteSeq(npcGuid[6]); + recvData.ReadByteSeq(npcGuid[4]); + + Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); + if (!unit) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageUnlock - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + if (player->IsVoidStorageUnlocked()) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageUnlock - Player (GUID: %u, name: %s) tried to unlock void storage a 2nd time.", player->GetGUIDLow(), player->GetName().c_str()); + return; + } + + player->ModifyMoney(-int64(VOID_STORAGE_UNLOCK)); + player->UnlockVoidStorage(); +} + +void WorldSession::HandleVoidStorageQuery(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_VOID_STORAGE_QUERY"); + Player* player = GetPlayer(); + + ObjectGuid npcGuid; + npcGuid[4] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[7] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + npcGuid[1] = recvData.ReadBit(); + npcGuid[2] = recvData.ReadBit(); + + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(npcGuid[6]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(npcGuid[0]); + recvData.ReadByteSeq(npcGuid[4]); + recvData.ReadByteSeq(npcGuid[2]); + + Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); + if (!unit) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageQuery - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + if (!player->IsVoidStorageUnlocked()) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageQuery - Player (GUID: %u, name: %s) queried void storage without unlocking it.", player->GetGUIDLow(), player->GetName().c_str()); + return; + } + + uint8 count = 0; + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + if (player->GetVoidStorageItem(i)) + ++count; + + WorldPacket data(SMSG_VOID_STORAGE_CONTENTS, 2 * count + (14 + 4 + 4 + 4 + 4) * count); + + data.WriteBits(count, 8); + + ByteBuffer itemData((14 + 4 + 4 + 4 + 4) * count); + + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + { + VoidStorageItem* item = player->GetVoidStorageItem(i); + if (!item) + continue; + + ObjectGuid itemId = item->ItemId; + ObjectGuid creatorGuid = item->CreatorGuid; + + data.WriteBit(creatorGuid[3]); + data.WriteBit(itemId[5]); + data.WriteBit(creatorGuid[6]); + data.WriteBit(creatorGuid[1]); + data.WriteBit(itemId[1]); + data.WriteBit(itemId[3]); + data.WriteBit(itemId[6]); + data.WriteBit(creatorGuid[5]); + data.WriteBit(creatorGuid[2]); + data.WriteBit(itemId[2]); + data.WriteBit(creatorGuid[4]); + data.WriteBit(itemId[0]); + data.WriteBit(itemId[4]); + data.WriteBit(itemId[7]); + data.WriteBit(creatorGuid[0]); + data.WriteBit(creatorGuid[7]); + + itemData.WriteByteSeq(creatorGuid[3]); + + itemData << uint32(item->ItemSuffixFactor); + + itemData.WriteByteSeq(creatorGuid[4]); + + itemData << uint32(i); + + itemData.WriteByteSeq(itemId[0]); + itemData.WriteByteSeq(itemId[6]); + itemData.WriteByteSeq(creatorGuid[0]); + itemData.WriteByteSeq(creatorGuid[1]); + + itemData << uint32(item->ItemRandomPropertyId); + + itemData.WriteByteSeq(itemId[4]); + itemData.WriteByteSeq(itemId[5]); + itemData.WriteByteSeq(itemId[2]); + itemData.WriteByteSeq(creatorGuid[2]); + itemData.WriteByteSeq(creatorGuid[6]); + itemData.WriteByteSeq(itemId[1]); + itemData.WriteByteSeq(itemId[3]); + itemData.WriteByteSeq(creatorGuid[5]); + itemData.WriteByteSeq(creatorGuid[7]); + + itemData << uint32(item->ItemEntry); + + itemData.WriteByteSeq(itemId[7]); + } + + data.FlushBits(); + data.append(itemData); + + SendPacket(&data); +} + +void WorldSession::HandleVoidStorageTransfer(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_VOID_STORAGE_TRANSFER"); + Player* player = GetPlayer(); + + // Read everything + + ObjectGuid npcGuid; + npcGuid[1] = recvData.ReadBit(); + + uint32 countDeposit = recvData.ReadBits(26); + + if (countDeposit > 9) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to deposit more than 9 items (%u).", player->GetGUIDLow(), player->GetName().c_str(), countDeposit); + return; + } + + std::vector<ObjectGuid> itemGuids(countDeposit); + for (uint32 i = 0; i < countDeposit; ++i) + { + itemGuids[i][4] = recvData.ReadBit(); + itemGuids[i][6] = recvData.ReadBit(); + itemGuids[i][7] = recvData.ReadBit(); + itemGuids[i][0] = recvData.ReadBit(); + itemGuids[i][1] = recvData.ReadBit(); + itemGuids[i][5] = recvData.ReadBit(); + itemGuids[i][3] = recvData.ReadBit(); + itemGuids[i][2] = recvData.ReadBit(); + } + + npcGuid[2] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + npcGuid[4] = recvData.ReadBit(); + + uint32 countWithdraw = recvData.ReadBits(26); + + if (countWithdraw > 9) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to withdraw more than 9 items (%u).", player->GetGUIDLow(), player->GetName().c_str(), countWithdraw); + return; + } + + std::vector<ObjectGuid> itemIds(countWithdraw); + for (uint32 i = 0; i < countWithdraw; ++i) + { + itemIds[i][4] = recvData.ReadBit(); + itemIds[i][7] = recvData.ReadBit(); + itemIds[i][1] = recvData.ReadBit(); + itemIds[i][0] = recvData.ReadBit(); + itemIds[i][2] = recvData.ReadBit(); + itemIds[i][3] = recvData.ReadBit(); + itemIds[i][5] = recvData.ReadBit(); + itemIds[i][6] = recvData.ReadBit(); + } + + npcGuid[7] = recvData.ReadBit(); + + for (uint32 i = 0; i < countDeposit; ++i) + { + recvData.ReadByteSeq(itemGuids[i][6]); + recvData.ReadByteSeq(itemGuids[i][1]); + recvData.ReadByteSeq(itemGuids[i][0]); + recvData.ReadByteSeq(itemGuids[i][2]); + recvData.ReadByteSeq(itemGuids[i][4]); + recvData.ReadByteSeq(itemGuids[i][5]); + recvData.ReadByteSeq(itemGuids[i][3]); + recvData.ReadByteSeq(itemGuids[i][7]); + } + + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(npcGuid[6]); + + for (uint32 i = 0; i < countWithdraw; ++i) + { + recvData.ReadByteSeq(itemIds[i][3]); + recvData.ReadByteSeq(itemIds[i][0]); + recvData.ReadByteSeq(itemIds[i][1]); + recvData.ReadByteSeq(itemIds[i][6]); + recvData.ReadByteSeq(itemIds[i][2]); + recvData.ReadByteSeq(itemIds[i][7]); + recvData.ReadByteSeq(itemIds[i][5]); + recvData.ReadByteSeq(itemIds[i][4]); + } + + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(npcGuid[4]); + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[2]); + recvData.ReadByteSeq(npcGuid[0]); + + Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); + if (!unit) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + if (!player->IsVoidStorageUnlocked()) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) queried void storage without unlocking it.", player->GetGUIDLow(), player->GetName().c_str()); + return; + } + + if (itemGuids.size() > player->GetNumOfVoidStorageFreeSlots()) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_FULL); + return; + } + + uint32 freeBagSlots = 0; + if (itemIds.size() != 0) + { + // make this a Player function + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + if (Bag* bag = player->GetBagByPos(i)) + freeBagSlots += bag->GetFreeSlots(); + for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + if (!player->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + ++freeBagSlots; + } + + if (itemIds.size() > freeBagSlots) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INVENTORY_FULL); + return; + } + + if (!player->HasEnoughMoney(uint64(itemGuids.size() * VOID_STORAGE_STORE_ITEM))) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_NOT_ENOUGH_MONEY); + return; + } + + std::pair<VoidStorageItem, uint8> depositItems[VOID_STORAGE_MAX_DEPOSIT]; + uint8 depositCount = 0; + for (std::vector<ObjectGuid>::iterator itr = itemGuids.begin(); itr != itemGuids.end(); ++itr) + { + Item* item = player->GetItemByGuid(*itr); + if (!item) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to deposit an invalid item (item guid: " UI64FMTD ").", player->GetGUIDLow(), player->GetName().c_str(), uint64(*itr)); + continue; + } + + VoidStorageItem itemVS(sObjectMgr->GenerateVoidStorageItemId(), item->GetEntry(), item->GetUInt64Value(ITEM_FIELD_CREATOR), item->GetItemRandomPropertyId(), item->GetItemSuffixFactor()); + + uint8 slot = player->AddVoidStorageItem(itemVS); + + depositItems[depositCount++] = std::make_pair(itemVS, slot); + + player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); + } + + int64 cost = depositCount * VOID_STORAGE_STORE_ITEM; + + player->ModifyMoney(-cost); + + VoidStorageItem withdrawItems[VOID_STORAGE_MAX_WITHDRAW]; + uint8 withdrawCount = 0; + for (std::vector<ObjectGuid>::iterator itr = itemIds.begin(); itr != itemIds.end(); ++itr) + { + uint8 slot; + VoidStorageItem* itemVS = player->GetVoidStorageItem(*itr, slot); + if (!itemVS) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) tried to withdraw an invalid item (id: " UI64FMTD ")", player->GetGUIDLow(), player->GetName().c_str(), uint64(*itr)); + continue; + } + + ItemPosCountVec dest; + InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemVS->ItemEntry, 1); + if (msg != EQUIP_ERR_OK) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INVENTORY_FULL); + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) couldn't withdraw item id " UI64FMTD " because inventory was full.", player->GetGUIDLow(), player->GetName().c_str(), uint64(*itr)); + return; + } + + Item* item = player->StoreNewItem(dest, itemVS->ItemEntry, true, itemVS->ItemRandomPropertyId); + item->SetUInt64Value(ITEM_FIELD_CREATOR, uint64(itemVS->CreatorGuid)); + item->SetBinding(true); + player->SendNewItem(item, 1, false, false, false); + + withdrawItems[withdrawCount++] = *itemVS; + + player->DeleteVoidStorageItem(slot); + } + + WorldPacket data(SMSG_VOID_STORAGE_TRANSFER_CHANGES, ((5 + 5 + (7 + 7) * depositCount + + 7 * withdrawCount) / 8) + 7 * withdrawCount + (7 + 7 + 4 * 4) * depositCount); + + data.WriteBits(depositCount, 5); + data.WriteBits(withdrawCount, 5); + + for (uint8 i = 0; i < depositCount; ++i) + { + ObjectGuid itemId = depositItems[i].first.ItemId; + ObjectGuid creatorGuid = depositItems[i].first.CreatorGuid; + data.WriteBit(creatorGuid[7]); + data.WriteBit(itemId[7]); + data.WriteBit(itemId[4]); + data.WriteBit(creatorGuid[6]); + data.WriteBit(creatorGuid[5]); + data.WriteBit(itemId[3]); + data.WriteBit(itemId[5]); + data.WriteBit(creatorGuid[4]); + data.WriteBit(creatorGuid[2]); + data.WriteBit(creatorGuid[0]); + data.WriteBit(creatorGuid[3]); + data.WriteBit(creatorGuid[1]); + data.WriteBit(itemId[2]); + data.WriteBit(itemId[0]); + data.WriteBit(itemId[1]); + data.WriteBit(itemId[6]); + } + + for (uint8 i = 0; i < withdrawCount; ++i) + { + ObjectGuid itemId = withdrawItems[i].ItemId; + data.WriteBit(itemId[1]); + data.WriteBit(itemId[7]); + data.WriteBit(itemId[3]); + data.WriteBit(itemId[5]); + data.WriteBit(itemId[6]); + data.WriteBit(itemId[2]); + data.WriteBit(itemId[4]); + data.WriteBit(itemId[0]); + } + + data.FlushBits(); + + for (uint8 i = 0; i < withdrawCount; ++i) + { + ObjectGuid itemId = withdrawItems[i].ItemId; + data.WriteByteSeq(itemId[3]); + data.WriteByteSeq(itemId[1]); + data.WriteByteSeq(itemId[0]); + data.WriteByteSeq(itemId[2]); + data.WriteByteSeq(itemId[7]); + data.WriteByteSeq(itemId[5]); + data.WriteByteSeq(itemId[6]); + data.WriteByteSeq(itemId[4]); + } + + for (uint8 i = 0; i < depositCount; ++i) + { + ObjectGuid itemId = depositItems[i].first.ItemId; + ObjectGuid creatorGuid = depositItems[i].first.CreatorGuid; + + data << uint32(depositItems[i].first.ItemSuffixFactor); + + data.WriteByteSeq(itemId[6]); + data.WriteByteSeq(itemId[4]); + data.WriteByteSeq(creatorGuid[4]); + data.WriteByteSeq(itemId[2]); + data.WriteByteSeq(creatorGuid[1]); + data.WriteByteSeq(creatorGuid[3]); + data.WriteByteSeq(itemId[3]); + data.WriteByteSeq(creatorGuid[0]); + data.WriteByteSeq(itemId[0]); + data.WriteByteSeq(creatorGuid[6]); + data.WriteByteSeq(itemId[5]); + data.WriteByteSeq(creatorGuid[5]); + data.WriteByteSeq(creatorGuid[7]); + + data << uint32(depositItems[i].first.ItemEntry); + + data.WriteByteSeq(itemId[1]); + + data << uint32(depositItems[i].second); // slot + + data.WriteByteSeq(creatorGuid[2]); + data.WriteByteSeq(itemId[7]); + + data << uint32(depositItems[i].first.ItemRandomPropertyId); + } + + SendPacket(&data); + + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_NO_ERROR); +} + +void WorldSession::HandleVoidSwapItem(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_VOID_SWAP_ITEM"); + + Player* player = GetPlayer(); + uint32 newSlot; + ObjectGuid npcGuid; + ObjectGuid itemId; + + recvData >> newSlot; + + npcGuid[2] = recvData.ReadBit(); + npcGuid[4] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + itemId[2] = recvData.ReadBit(); + itemId[6] = recvData.ReadBit(); + itemId[5] = recvData.ReadBit(); + npcGuid[1] = recvData.ReadBit(); + npcGuid[7] = recvData.ReadBit(); + itemId[3] = recvData.ReadBit(); + itemId[7] = recvData.ReadBit(); + itemId[0] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + itemId[1] = recvData.ReadBit(); + itemId[4] = recvData.ReadBit(); + + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(itemId[3]); + recvData.ReadByteSeq(itemId[2]); + recvData.ReadByteSeq(itemId[4]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[0]); + recvData.ReadByteSeq(itemId[6]); + recvData.ReadByteSeq(itemId[1]); + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(itemId[5]); + recvData.ReadByteSeq(npcGuid[6]); + recvData.ReadByteSeq(itemId[0]); + recvData.ReadByteSeq(npcGuid[2]); + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[4]); + recvData.ReadByteSeq(itemId[7]); + + Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); + if (!unit) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidSwapItem - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + if (!player->IsVoidStorageUnlocked()) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidSwapItem - Player (GUID: %u, name: %s) queried void storage without unlocking it.", player->GetGUIDLow(), player->GetName().c_str()); + return; + } + + uint8 oldSlot; + if (!player->GetVoidStorageItem(itemId, oldSlot)) + { + TC_LOG_DEBUG("network", "WORLD: HandleVoidSwapItem - Player (GUID: %u, name: %s) requested swapping an invalid item (slot: %u, itemid: " UI64FMTD ").", player->GetGUIDLow(), player->GetName().c_str(), newSlot, uint64(itemId)); + return; + } + + bool usedSrcSlot = player->GetVoidStorageItem(oldSlot) != NULL; // should be always true + bool usedDestSlot = player->GetVoidStorageItem(newSlot) != NULL; + ObjectGuid itemIdDest; + if (usedDestSlot) + itemIdDest = player->GetVoidStorageItem(newSlot)->ItemId; + + if (!player->SwapVoidStorageItem(oldSlot, newSlot)) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); + return; + } + + WorldPacket data(SMSG_VOID_ITEM_SWAP_RESPONSE, 1 + (usedSrcSlot + usedDestSlot) * (1 + 7 + 4)); + + data.WriteBit(!usedDestSlot); + data.WriteBit(!usedSrcSlot); + + if (usedSrcSlot) + { + data.WriteBit(itemId[5]); + data.WriteBit(itemId[2]); + data.WriteBit(itemId[1]); + data.WriteBit(itemId[4]); + data.WriteBit(itemId[0]); + data.WriteBit(itemId[6]); + data.WriteBit(itemId[7]); + data.WriteBit(itemId[3]); + } + + data.WriteBit(!usedDestSlot); // unk + + if (usedDestSlot) + { + data.WriteBit(itemIdDest[7]); + data.WriteBit(itemIdDest[3]); + data.WriteBit(itemIdDest[4]); + data.WriteBit(itemIdDest[0]); + data.WriteBit(itemIdDest[5]); + data.WriteBit(itemIdDest[1]); + data.WriteBit(itemIdDest[2]); + data.WriteBit(itemIdDest[6]); + } + + data.WriteBit(!usedSrcSlot); // unk + + data.FlushBits(); + + if (usedDestSlot) + { + data.WriteByteSeq(itemIdDest[4]); + data.WriteByteSeq(itemIdDest[6]); + data.WriteByteSeq(itemIdDest[5]); + data.WriteByteSeq(itemIdDest[2]); + data.WriteByteSeq(itemIdDest[3]); + data.WriteByteSeq(itemIdDest[1]); + data.WriteByteSeq(itemIdDest[7]); + data.WriteByteSeq(itemIdDest[0]); + } + + if (usedSrcSlot) + { + data.WriteByteSeq(itemId[6]); + data.WriteByteSeq(itemId[3]); + data.WriteByteSeq(itemId[5]); + data.WriteByteSeq(itemId[0]); + data.WriteByteSeq(itemId[1]); + data.WriteByteSeq(itemId[2]); + data.WriteByteSeq(itemId[4]); + data.WriteByteSeq(itemId[7]); + } + + if (usedDestSlot) + data << uint32(oldSlot); + + if (usedSrcSlot) + data << uint32(newSlot); + + SendPacket(&data); +} diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index c46d9002604..e37e6847bdd 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -164,11 +164,7 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 InstanceId) void InstanceSaveManager::UnloadInstanceSave(uint32 InstanceId) { if (InstanceSave* save = GetInstanceSave(InstanceId)) - { save->UnloadIfEmpty(); - if (save->m_toDelete) - delete save; - } } InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset) diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h index 0a2af4b73ee..701776bb57d 100644 --- a/src/server/game/Instances/InstanceSaveMgr.h +++ b/src/server/game/Instances/InstanceSaveMgr.h @@ -120,16 +120,16 @@ class InstanceSave but that would depend on a lot of things that can easily change in future */ Difficulty GetDifficulty() const { return m_difficulty; } - typedef std::list<Player*> PlayerListType; - typedef std::list<Group*> GroupListType; - private: - bool UnloadIfEmpty(); /* used to flag the InstanceSave as to be deleted, so the caller can delete it */ void SetToDelete(bool toDelete) { m_toDelete = toDelete; } + typedef std::list<Player*> PlayerListType; + typedef std::list<Group*> GroupListType; + private: + bool UnloadIfEmpty(); /* the only reason the instSave-object links are kept is because the object-instSave links need to be broken at reset time */ /// @todo: Check if maybe it's enough to just store the number of players/groups diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index adef21fe7a2..46e1352df3f 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -334,7 +334,7 @@ void InstanceScript::DoUpdateAchievementCriteria(AchievementCriteriaTypes type, if (!PlayerList.isEmpty()) for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (Player* player = i->GetSource()) - player->UpdateAchievementCriteria(type, miscValue1, miscValue2, unit); + player->UpdateAchievementCriteria(type, miscValue1, miscValue2, 0, unit); } // Start timed achievement for all players in instance @@ -414,6 +414,7 @@ void InstanceScript::SendEncounterUnit(uint32 type, Unit* unit /*= NULL*/, uint8 case ENCOUNTER_FRAME_ADD_TIMER: case ENCOUNTER_FRAME_ENABLE_OBJECTIVE: case ENCOUNTER_FRAME_DISABLE_OBJECTIVE: + case ENCOUNTER_FRAME_SET_COMBAT_RES_LIMIT: data << uint8(param1); break; case ENCOUNTER_FRAME_UPDATE_OBJECTIVE: @@ -421,6 +422,8 @@ void InstanceScript::SendEncounterUnit(uint32 type, Unit* unit /*= NULL*/, uint8 data << uint8(param2); break; case ENCOUNTER_FRAME_UNK7: + case ENCOUNTER_FRAME_ADD_COMBAT_RES_LIMIT: + case ENCOUNTER_FRAME_RESET_COMBAT_RES_LIMIT: default: break; } @@ -445,7 +448,7 @@ void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 credi if (encounter->lastEncounterDungeon) { dungeonId = encounter->lastEncounterDungeon; - TC_LOG_DEBUG("lfg", "UpdateEncounterState: Instance %s (instanceId %u) completed encounter %s. Credit Dungeon: %u", instance->GetMapName(), instance->GetInstanceId(), encounter->dbcEntry->encounterName[0], dungeonId); + TC_LOG_DEBUG("lfg", "UpdateEncounterState: Instance %s (instanceId %u) completed encounter %s. Credit Dungeon: %u", instance->GetMapName(), instance->GetInstanceId(), encounter->dbcEntry->encounterName, dungeonId); break; } } @@ -466,3 +469,11 @@ void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 credi } } } + +void InstanceScript::UpdatePhasing() +{ + Map::PlayerList const& players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->GetSource()) + player->UpdatePhasing(); +} diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index f379572961c..7e9be651e61 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -40,14 +40,17 @@ typedef std::set<uint64> MinionSet; enum EncounterFrameType { - ENCOUNTER_FRAME_ENGAGE = 0, - ENCOUNTER_FRAME_DISENGAGE = 1, - ENCOUNTER_FRAME_UPDATE_PRIORITY = 2, - ENCOUNTER_FRAME_ADD_TIMER = 3, - ENCOUNTER_FRAME_ENABLE_OBJECTIVE = 4, - ENCOUNTER_FRAME_UPDATE_OBJECTIVE = 5, - ENCOUNTER_FRAME_DISABLE_OBJECTIVE = 6, - ENCOUNTER_FRAME_UNK7 = 7 // Seems to have something to do with sorting the encounter units + ENCOUNTER_FRAME_SET_COMBAT_RES_LIMIT = 0, + ENCOUNTER_FRAME_RESET_COMBAT_RES_LIMIT = 1, + ENCOUNTER_FRAME_ENGAGE = 2, + ENCOUNTER_FRAME_DISENGAGE = 3, + ENCOUNTER_FRAME_UPDATE_PRIORITY = 4, + ENCOUNTER_FRAME_ADD_TIMER = 5, + ENCOUNTER_FRAME_ENABLE_OBJECTIVE = 6, + ENCOUNTER_FRAME_UPDATE_OBJECTIVE = 7, + ENCOUNTER_FRAME_DISABLE_OBJECTIVE = 8, + ENCOUNTER_FRAME_UNK7 = 9, // Seems to have something to do with sorting the encounter units + ENCOUNTER_FRAME_ADD_COMBAT_RES_LIMIT = 10 }; enum EncounterState @@ -214,6 +217,9 @@ class InstanceScript : public ZoneScript virtual void FillInitialWorldStates(WorldPacket& /*data*/) { } + // ReCheck PhaseTemplate related conditions + void UpdatePhasing(); + protected: void SetBossNumber(uint32 number) { bosses.resize(number); } void LoadDoorData(DoorData const* data); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 270af559f0b..60475382d5e 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -864,17 +864,21 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) { b << uint32(0); // gold b << uint8(0); // item count + b << uint8(0); // currency count return b; } Loot &l = lv.loot; uint8 itemsShown = 0; + uint8 currenciesShown = 0; b << uint32(l.gold); //gold size_t count_pos = b.wpos(); // pos of item count byte b << uint8(0); // item count placeholder + size_t currency_count_pos = b.wpos(); // pos of currency count byte + b << uint8(0); // currency count placeholder switch (lv.permission) { @@ -1062,8 +1066,9 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) } } - //update number of items shown + //update number of items and currencies shown b.put<uint8>(count_pos, itemsShown); + b.put<uint8>(currency_count_pos, currenciesShown); return b; } @@ -1545,16 +1550,17 @@ void LoadLootTemplates_Disenchant() LootIdSet lootIdSet, lootIdSetUsed; uint32 count = LootTemplates_Disenchant.LoadAndCollectLootIds(lootIdSet); - ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore(); - for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr) + for (uint32 i = 0; i < sItemDisenchantLootStore.GetNumRows(); ++i) { - if (uint32 lootid = itr->second.DisenchantID) - { - if (lootIdSet.find(lootid) == lootIdSet.end()) - LootTemplates_Disenchant.ReportNotExistedId(lootid); - else - lootIdSetUsed.insert(lootid); - } + ItemDisenchantLootEntry const* disenchant = sItemDisenchantLootStore.LookupEntry(i); + if (!disenchant) + continue; + + uint32 lootid = disenchant->Id; + if (lootIdSet.find(lootid) == lootIdSet.end()) + LootTemplates_Disenchant.ReportNotExistedId(lootid); + else + lootIdSetUsed.insert(lootid); } for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr) diff --git a/src/server/game/Mails/Mail.h b/src/server/game/Mails/Mail.h index e3fc42f3f9e..abae99330c0 100644 --- a/src/server/game/Mails/Mail.h +++ b/src/server/game/Mails/Mail.h @@ -126,13 +126,13 @@ class MailDraft public: // Accessors uint16 GetMailTemplateId() const { return m_mailTemplateId; } std::string const& GetSubject() const { return m_subject; } - uint32 GetMoney() const { return m_money; } - uint32 GetCOD() const { return m_COD; } + uint64 GetMoney() const { return m_money; } + uint64 GetCOD() const { return m_COD; } std::string const& GetBody() const { return m_body; } public: // modifiers MailDraft& AddItem(Item* item); - MailDraft& AddMoney(uint32 money) { m_money = money; return *this; } + MailDraft& AddMoney(uint64 money) { m_money = money; return *this; } MailDraft& AddCOD(uint32 COD) { m_COD = COD; return *this; } public: // finishers @@ -150,8 +150,8 @@ class MailDraft MailItemMap m_items; // Keep the items in a map to avoid duplicate guids (which can happen), store only low part of guid - uint32 m_money; - uint32 m_COD; + uint64 m_money; + uint64 m_COD; }; struct MailItemInfo @@ -167,7 +167,7 @@ struct Mail uint8 messageType; uint8 stationery; uint16 mailTemplateId; - uint32 sender; + uint32 sender; // TODO: change to uint64 and store full guids uint32 receiver; std::string subject; std::string body; @@ -175,8 +175,8 @@ struct Mail std::vector<uint32> removedItems; time_t expire_time; time_t deliver_time; - uint32 money; - uint32 COD; + uint64 money; + uint64 COD; uint32 checked; MailState state; diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index b0164b77f1c..75301da32ed 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -575,7 +575,7 @@ bool Map::AddToMap(Transport* obj) { if (itr->GetSource()->GetTransport() != obj) { - UpdateData data; + UpdateData data(GetId()); obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource()); WorldPacket packet; data.BuildPacket(&packet); @@ -835,13 +835,13 @@ void Map::RemoveFromMap(Transport* obj, bool remove) Map::PlayerList const& players = GetPlayers(); if (!players.isEmpty()) { - UpdateData data; + UpdateData data(GetId()); obj->BuildOutOfRangeUpdateBlock(&data); WorldPacket packet; data.BuildPacket(&packet); for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - if (itr->GetSource()->GetTransport() != obj) - itr->GetSource()->SendDirectMessage(&packet); + if (itr->GetSource()->GetTransport() != obj) + itr->GetSource()->SendDirectMessage(&packet); } if (_transportsUpdateIter != _transports.end()) @@ -2469,7 +2469,7 @@ bool Map::CheckGridIntegrity(Creature* c, bool moved) const char const* Map::GetMapName() const { - return i_mapEntry ? i_mapEntry->name[sWorld->GetDefaultDbcLocale()] : "UNNAMEDMAP\x0"; + return i_mapEntry ? i_mapEntry->name : "UNNAMEDMAP\x0"; } void Map::UpdateObjectVisibility(WorldObject* obj, Cell cell, CellCoord cellpair) @@ -2498,7 +2498,7 @@ void Map::SendInitSelf(Player* player) { TC_LOG_INFO("maps", "Creating player data for himself %u", player->GetGUIDLow()); - UpdateData data; + UpdateData data(player->GetMapId()); // attach to player data current transport data if (Transport* transport = player->GetTransport()) @@ -2523,9 +2523,9 @@ void Map::SendInitSelf(Player* player) void Map::SendInitTransports(Player* player) { // Hack to send out transports - UpdateData transData; + UpdateData transData(player->GetMapId()); for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i) - if (*i != player->GetTransport()) + if (*i != player->GetTransport() && player->IsInPhase(*i)) (*i)->BuildCreateUpdateBlockForPlayer(&transData, player); WorldPacket packet; @@ -2536,7 +2536,7 @@ void Map::SendInitTransports(Player* player) void Map::SendRemoveTransports(Player* player) { // Hack to send out transports - UpdateData transData; + UpdateData transData(player->GetMapId()); for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i) if (*i != player->GetTransport()) (*i)->BuildOutOfRangeUpdateBlock(&transData); @@ -2546,6 +2546,26 @@ void Map::SendRemoveTransports(Player* player) player->GetSession()->SendPacket(&packet); } +void Map::SendUpdateTransportVisibility(Player* player, std::set<uint32> const& previousPhases) +{ + // Hack to send out transports + UpdateData transData(player->GetMapId()); + for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i) + { + if (*i == player->GetTransport()) + continue; + + if (player->IsInPhase(*i) && !Trinity::Containers::Intersects(previousPhases.begin(), previousPhases.end(), (*i)->GetPhases().begin(), (*i)->GetPhases().end())) + (*i)->BuildCreateUpdateBlockForPlayer(&transData, player); + else if (!player->IsInPhase(*i)) + (*i)->BuildOutOfRangeUpdateBlock(&transData); + } + + WorldPacket packet; + transData.BuildPacket(&packet); + player->GetSession()->SendPacket(&packet); +} + inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y) { if (x >= MAX_NUMBER_OF_GRIDS || y >= MAX_NUMBER_OF_GRIDS) @@ -2647,6 +2667,9 @@ void Map::RemoveAllObjectsInRemoveList() case TYPEID_DYNAMICOBJECT: RemoveFromMap(obj->ToDynObject(), true); break; + case TYPEID_AREATRIGGER: + RemoveFromMap((AreaTrigger*)obj, true); + break; case TYPEID_GAMEOBJECT: { GameObject* go = obj->ToGameObject(); @@ -2794,11 +2817,13 @@ template bool Map::AddToMap(Corpse*); template bool Map::AddToMap(Creature*); template bool Map::AddToMap(GameObject*); template bool Map::AddToMap(DynamicObject*); +template bool Map::AddToMap(AreaTrigger*); template void Map::RemoveFromMap(Corpse*, bool); template void Map::RemoveFromMap(Creature*, bool); template void Map::RemoveFromMap(GameObject*, bool); template void Map::RemoveFromMap(DynamicObject*, bool); +template void Map::RemoveFromMap(AreaTrigger*, bool); /* ******* Dungeon Instance Maps ******* */ @@ -2968,10 +2993,11 @@ bool InstanceMap::AddPlayerToMap(Player* player) // players also become permanently bound when they enter if (groupBind->perm) { - WorldPacket data(SMSG_INSTANCE_LOCK_WARNING_QUERY, 9); + WorldPacket data(SMSG_INSTANCE_LOCK_WARNING_QUERY, 10); data << uint32(60000); data << uint32(i_data ? i_data->GetCompletedEncounterMask() : 0); data << uint8(0); + data << uint8(0); // events it throws: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START player->GetSession()->SendPacket(&data); player->SetPendingBind(mapSave->GetInstanceId(), 60000); } @@ -3441,6 +3467,7 @@ void Map::SendZoneDynamicInfo(Player* player) { WorldPacket data(SMSG_PLAY_MUSIC, 4); data << uint32(music); + data << uint64(player->GetGUID()); player->SendDirectMessage(&data); } @@ -3473,13 +3500,15 @@ void Map::SetZoneMusic(uint32 zoneId, uint32 musicId) Map::PlayerList const& players = GetPlayers(); if (!players.isEmpty()) { - WorldPacket data(SMSG_PLAY_MUSIC, 4); - data << uint32(musicId); - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) if (Player* player = itr->GetSource()) if (player->GetZoneId() == zoneId) + { + WorldPacket data(SMSG_PLAY_MUSIC, 4); + data << uint32(musicId); + data << uint64(player->GetGUID()); player->SendDirectMessage(&data); + } } } diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 70198cb20a3..c194f4dccd7 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -474,6 +474,7 @@ class Map : public GridRefManager<NGridType> bool ContainsGameObjectModel(const GameObjectModel& model) const { return _dynamicTree.contains(model);} bool getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist); + virtual uint32 GetOwnerGuildId(uint32 /*team*/ = TEAM_OTHER) const { return 0; } /* RESPAWN TIMES */ @@ -507,6 +508,7 @@ class Map : public GridRefManager<NGridType> void SendInitTransports(Player* player); void SendRemoveTransports(Player* player); + void SendUpdateTransportVisibility(Player* player, std::set<uint32> const& previousPhases); void SendZoneDynamicInfo(Player* player); void SetZoneMusic(uint32 zoneId, uint32 musicId); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 9c023b86bc9..cc408988428 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -145,7 +145,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) if (player->IsGameMaster()) return true; - char const* mapName = entry->name[player->GetSession()->GetSessionDbcLocale()]; + char const* mapName = entry->name; Group* group = player->GetGroup(); if (entry->IsRaid()) diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index 28869d264c4..ba7d3784157 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -348,7 +348,7 @@ void TransportMgr::AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, animNode.Path[timeSeg] = node; } -Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map* map /*= NULL*/) +Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map* map /*= NULL*/, uint32 phaseid /*= 0*/, uint32 phasegroup /*= 0*/) { // instance case, execute GetGameObjectEntry hook if (map) @@ -388,6 +388,13 @@ Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map* return NULL; } + if (phaseid) + trans->SetInPhase(phaseid, false, true); + + if (phasegroup) + for (auto ph : GetPhasesForGroup(phasegroup)) + trans->SetInPhase(ph, false, true); + if (MapEntry const* mapEntry = sMapStore.LookupEntry(mapId)) { if (mapEntry->Instanceable() != tInfo->inInstance) @@ -416,7 +423,7 @@ void TransportMgr::SpawnContinentTransports() uint32 oldMSTime = getMSTime(); - QueryResult result = WorldDatabase.Query("SELECT guid, entry FROM transports"); + QueryResult result = WorldDatabase.Query("SELECT guid, entry, phaseid, phasegroup FROM transports"); uint32 count = 0; if (result) @@ -426,10 +433,12 @@ void TransportMgr::SpawnContinentTransports() Field* fields = result->Fetch(); uint32 guid = fields[0].GetUInt32(); uint32 entry = fields[1].GetUInt32(); + uint32 phaseid = fields[2].GetUInt32(); + uint32 phasegroup = fields[3].GetUInt32(); if (TransportTemplate const* tInfo = GetTransportTemplate(entry)) if (!tInfo->inInstance) - if (CreateTransport(entry, guid)) + if (CreateTransport(entry, guid, nullptr, phaseid, phasegroup)) ++count; } while (result->NextRow()); diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 04c372cc526..94a4ba335b1 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -109,7 +109,7 @@ class TransportMgr void LoadTransportTemplates(); // Creates a transport using given GameObject template entry - Transport* CreateTransport(uint32 entry, uint32 guid = 0, Map* map = NULL); + Transport* CreateTransport(uint32 entry, uint32 guid = 0, Map* map = nullptr, uint32 phaseid = 0, uint32 phasegroup = 0); // Spawns all continent transports, used at core startup void SpawnContinentTransports(); diff --git a/src/server/game/Miscellaneous/Formulas.h b/src/server/game/Miscellaneous/Formulas.h index 8d0e97dc765..924320ac198 100644 --- a/src/server/game/Miscellaneous/Formulas.h +++ b/src/server/game/Miscellaneous/Formulas.h @@ -128,6 +128,9 @@ namespace Trinity case CONTENT_71_80: nBaseExp = 580; break; + case CONTENT_81_85: + nBaseExp = 1878; + break; default: TC_LOG_ERROR("misc", "BaseGain: Unsupported content level %u", content); nBaseExp = 45; @@ -221,6 +224,26 @@ namespace Trinity return rate; } } // namespace Trinity::XP + + namespace Currency + { + inline uint32 ConquestRatingCalculator(uint32 rate) + { + if (rate <= 1500) + return 1350; // Default conquest points + else if (rate > 3000) + rate = 3000; + + // http://www.arenajunkies.com/topic/179536-conquest-point-cap-vs-personal-rating-chart/page__st__60#entry3085246 + return uint32(1.4326 * ((1511.26 / (1 + 1639.28 / exp(0.00412 * rate))) + 850.15)); + } + + inline uint32 BgConquestRatingCalculator(uint32 rate) + { + // WowWiki: Battleground ratings receive a bonus of 22.2% to the cap they generate + return uint32((ConquestRatingCalculator(rate) * 1.222f) + 0.5f); + } + } // namespace Trinity::Currency } // namespace Trinity #endif diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 3a680e30217..68a0687dc24 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -205,7 +205,15 @@ enum TrinityStrings LANG_LIQUID_STATUS = 175, LANG_INVALID_GAMEOBJECT_TYPE = 176, LANG_GAMEOBJECT_DAMAGED = 177, - // Room for more level 1 178-199 not used + + LANG_PHASING_SUCCESS = 178, + LANG_PHASING_FAILED = 179, + LANG_PHASING_LAST_PHASE = 180, + LANG_PHASING_LIST = 181, + LANG_PHASING_PHASEMASK = 182, + LANG_PHASING_REPORT_STATUS = 183, + LANG_PHASING_NO_DEFINITIONS = 184, // Phasing + // Room for more level 1 185-199 not used // level 2 chat LANG_NO_SELECTION = 200, @@ -728,12 +736,12 @@ enum TrinityStrings LANG_DEBUG_ARENA_OFF = 738, LANG_DEBUG_BG_ON = 739, LANG_DEBUG_BG_OFF = 740, - LANG_DIST_ARENA_POINTS_START = 741, - LANG_DIST_ARENA_POINTS_ONLINE_START = 742, - LANG_DIST_ARENA_POINTS_ONLINE_END = 743, - LANG_DIST_ARENA_POINTS_TEAM_START = 744, - LANG_DIST_ARENA_POINTS_TEAM_END = 745, - LANG_DIST_ARENA_POINTS_END = 746, +// LANG_DIST_ARENA_POINTS_START = 741, +// LANG_DIST_ARENA_POINTS_ONLINE_START = 742, +// LANG_DIST_ARENA_POINTS_ONLINE_END = 743, +// LANG_DIST_ARENA_POINTS_TEAM_START = 744, +// LANG_DIST_ARENA_POINTS_TEAM_END = 745, +// LANG_DIST_ARENA_POINTS_END = 746, LANG_BG_DISABLED = 747, LANG_ARENA_DISABLED = 748, // = 749, see LANG_PINFO_ACC_OS @@ -881,7 +889,8 @@ enum TrinityStrings LANG_CHARACTER_DELETED_LIST_LINE_CHAT = 1026, LANG_SQLDRIVER_QUERY_LOGGING_ENABLED = 1027, LANG_SQLDRIVER_QUERY_LOGGING_DISABLED = 1028, - // Room for more level 4 1029-1099 not used + LANG_ACCOUNT_INVALID_BNET_NAME = 1029, + // Room for more level 4 1030-1099 not used // Level 3 (continue) LANG_ACCOUNT_SETADDON = 1100, diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 7a48e016af0..833e4f7c7bc 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -50,7 +50,8 @@ enum Expansions EXPANSION_CLASSIC = 0, EXPANSION_THE_BURNING_CRUSADE = 1, EXPANSION_WRATH_OF_THE_LICH_KING = 2, - MAX_EXPANSIONS = 3 + EXPANSION_CATACLYSM = 3, + MAX_EXPANSIONS = 4 }; enum Gender @@ -72,9 +73,9 @@ enum Races RACE_TAUREN = 6, RACE_GNOME = 7, RACE_TROLL = 8, - //RACE_GOBLIN = 9, + RACE_GOBLIN = 9, RACE_BLOODELF = 10, - RACE_DRAENEI = 11 + RACE_DRAENEI = 11, //RACE_FEL_ORC = 12, //RACE_NAGA = 13, //RACE_BROKEN = 14, @@ -84,21 +85,23 @@ enum Races //RACE_FOREST_TROLL = 18, //RACE_TAUNKA = 19, //RACE_NORTHREND_SKELETON = 20, - //RACE_ICE_TROLL = 21 + //RACE_ICE_TROLL = 21, + RACE_WORGEN = 22, + //RACE_GILNEAN = 23 }; // max+1 for player race -#define MAX_RACES 12 +#define MAX_RACES 23 #define RACEMASK_ALL_PLAYABLE \ ((1<<(RACE_HUMAN-1)) |(1<<(RACE_ORC-1)) |(1<<(RACE_DWARF-1)) | \ (1<<(RACE_NIGHTELF-1))|(1<<(RACE_UNDEAD_PLAYER-1))|(1<<(RACE_TAUREN-1)) | \ (1<<(RACE_GNOME-1)) |(1<<(RACE_TROLL-1)) |(1<<(RACE_BLOODELF-1))| \ - (1<<(RACE_DRAENEI-1))) + (1<<(RACE_DRAENEI-1)) |(1<<(RACE_GOBLIN-1)) |(1<<(RACE_WORGEN-1))) #define RACEMASK_ALLIANCE \ ((1<<(RACE_HUMAN-1)) | (1<<(RACE_DWARF-1)) | (1<<(RACE_NIGHTELF-1)) | \ - (1<<(RACE_GNOME-1)) | (1<<(RACE_DRAENEI-1))) + (1<<(RACE_GNOME-1)) | (1<<(RACE_DRAENEI-1)) | (1<<(RACE_WORGEN-1))) #define RACEMASK_HORDE RACEMASK_ALL_PLAYABLE & ~RACEMASK_ALLIANCE @@ -158,7 +161,7 @@ enum ReputationRank #define MIN_REPUTATION_RANK (REP_HATED) #define MAX_REPUTATION_RANK 8 -#define MAX_SPILLOVER_FACTIONS 4 +#define MAX_SPILLOVER_FACTIONS 5 enum MoneyConstants { @@ -184,14 +187,20 @@ enum Powers POWER_RAGE = 1, POWER_FOCUS = 2, POWER_ENERGY = 3, - POWER_HAPPINESS = 4, - POWER_RUNE = 5, + POWER_UNUSED = 4, + POWER_RUNES = 5, POWER_RUNIC_POWER = 6, - MAX_POWERS = 7, - POWER_ALL = 127, // default for class? + POWER_SOUL_SHARDS = 7, + POWER_ECLIPSE = 8, + POWER_HOLY_POWER = 9, + POWER_ALTERNATE_POWER = 10, // Used in some quests + MAX_POWERS = 11, + POWER_ALL = 127, // default for class? POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) }; +#define MAX_POWERS_PER_CLASS 5 + enum SpellSchools { SPELL_SCHOOL_NORMAL = 0, @@ -436,7 +445,7 @@ enum SpellAttr4 SPELL_ATTR4_UNK13 = 0x00002000, // 13 SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS = 0x00004000, // 14 doesn't break auras by damage from these spells SPELL_ATTR4_UNK15 = 0x00008000, // 15 - SPELL_ATTR4_NOT_USABLE_IN_ARENA = 0x00010000, // 16 + SPELL_ATTR4_NOT_USABLE_IN_ARENA_OR_RATED_BG = 0x00010000, // 16 Cannot be used in both Arenas or Rated Battlegrounds SPELL_ATTR4_USABLE_IN_ARENA = 0x00020000, // 17 SPELL_ATTR4_AREA_TARGET_CHAIN = 0x00040000, // 18 (NYI)hits area targets one after another instead of all at once SPELL_ATTR4_UNK19 = 0x00080000, // 19 proc dalayed, after damage or don't proc on absorb? @@ -533,7 +542,7 @@ enum SpellAttr7 SPELL_ATTR7_REACTIVATE_AT_RESURRECT = 0x00000004, // 2 Paladin's auras and 65607 only. SPELL_ATTR7_IS_CHEAT_SPELL = 0x00000008, // 3 Cannot cast if caster doesn't have UnitFlag2 & UNIT_FLAG2_ALLOW_CHEAT_SPELLS SPELL_ATTR7_UNK4 = 0x00000010, // 4 Only 47883 (Soulstone Resurrection) and test spell. - SPELL_ATTR7_SUMMON_PLAYER_TOTEM = 0x00000020, // 5 Only Shaman player totems. + SPELL_ATTR7_SUMMON_TOTEM = 0x00000020, // 5 Only Shaman totems. SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE = 0x00000040, // 6 Does not cause spell pushback on damage SPELL_ATTR7_UNK7 = 0x00000080, // 7 66218 (Launch) spell. SPELL_ATTR7_HORDE_ONLY = 0x00000100, // 8 Teleports, mounts and other spells. @@ -562,11 +571,120 @@ enum SpellAttr7 SPELL_ATTR7_CLIENT_INDICATOR = 0x80000000 }; +enum SpellAttr8 +{ + SPELL_ATTR8_CANT_MISS = 0x00000001, // 0 + SPELL_ATTR8_UNK1 = 0x00000002, // 1 + SPELL_ATTR8_UNK2 = 0x00000004, // 2 + SPELL_ATTR8_UNK3 = 0x00000008, // 3 + SPELL_ATTR8_UNK4 = 0x00000010, // 4 + SPELL_ATTR8_UNK5 = 0x00000020, // 5 + SPELL_ATTR8_UNK6 = 0x00000040, // 6 + SPELL_ATTR8_UNK7 = 0x00000080, // 7 + SPELL_ATTR8_AFFECT_PARTY_AND_RAID = 0x00000100, // 8 Nearly all spells have "all party and raid" in description + SPELL_ATTR8_DONT_RESET_PERIODIC_TIMER = 0x00000200, // 9 Periodic auras with this flag keep old periodic timer when refreshing at close to one tick remaining (kind of anti DoT clipping) + SPELL_ATTR8_NAME_CHANGED_DURING_TRANSFORM = 0x00000400, // 10 according to wowhead comments, name changes, title remains + SPELL_ATTR8_UNK11 = 0x00000800, // 11 + SPELL_ATTR8_AURA_SEND_AMOUNT = 0x00001000, // 12 Aura must have flag AFLAG_ANY_EFFECT_AMOUNT_SENT to send amount + SPELL_ATTR8_UNK13 = 0x00002000, // 13 + SPELL_ATTR8_UNK14 = 0x00004000, // 14 + SPELL_ATTR8_WATER_MOUNT = 0x00008000, // 15 only one River Boat used in Thousand Needles + SPELL_ATTR8_UNK16 = 0x00010000, // 16 + SPELL_ATTR8_UNK17 = 0x00020000, // 17 + SPELL_ATTR8_REMEMBER_SPELLS = 0x00040000, // 18 at some point in time, these auras remember spells and allow to cast them later + SPELL_ATTR8_USE_COMBO_POINTS_ON_ANY_TARGET = 0x00080000, // 19 allows to consume combo points from dead targets + SPELL_ATTR8_ARMOR_SPECIALIZATION = 0x00100000, // 20 + SPELL_ATTR8_UNK21 = 0x00200000, // 21 + SPELL_ATTR8_UNK22 = 0x00400000, // 22 + SPELL_ATTR8_BATTLE_RESURRECTION = 0x00800000, // 23 Used to limit the Amount of Resurrections in Boss Encounters + SPELL_ATTR8_HEALING_SPELL = 0x01000000, // 24 + SPELL_ATTR8_UNK25 = 0x02000000, // 25 + SPELL_ATTR8_RAID_MARKER = 0x04000000, // 26 probably spell no need learn to cast + SPELL_ATTR8_UNK27 = 0x08000000, // 27 + SPELL_ATTR8_NOT_IN_BG_OR_ARENA = 0x10000000, // 28 not allow to cast or deactivate currently active effect, not sure about Fast Track + SPELL_ATTR8_MASTERY_SPECIALIZATION = 0x20000000, // 29 + SPELL_ATTR8_UNK30 = 0x40000000, // 30 + SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG = 0x80000000 // 31 Do not check UNIT_FLAG_IMMUNE_TO_PC in IsValidAttackTarget +}; + +enum SpellAttr9 +{ + SPELL_ATTR9_UNK0 = 0x00000001, // 0 + SPELL_ATTR9_UNK1 = 0x00000002, // 1 + SPELL_ATTR9_RESTRICTED_FLIGHT_AREA = 0x00000004, // 2 Dalaran and Wintergrasp flight area auras have it + SPELL_ATTR9_UNK3 = 0x00000008, // 3 + SPELL_ATTR9_SPECIAL_DELAY_CALCULATION = 0x00000010, // 4 + SPELL_ATTR9_SUMMON_PLAYER_TOTEM = 0x00000020, // 5 + SPELL_ATTR9_UNK6 = 0x00000040, // 6 + SPELL_ATTR9_UNK7 = 0x00000080, // 7 + SPELL_ATTR9_AIMED_SHOT = 0x00000100, // 8 + SPELL_ATTR9_NOT_USABLE_IN_ARENA = 0x00000200, // 9 Cannot be used in arenas + SPELL_ATTR9_UNK10 = 0x00000400, // 10 + SPELL_ATTR9_UNK11 = 0x00000800, // 11 + SPELL_ATTR9_UNK12 = 0x00001000, // 12 + SPELL_ATTR9_SLAM = 0x00002000, // 13 + SPELL_ATTR9_USABLE_IN_RATED_BATTLEGROUNDS = 0x00004000, // 14 Can be used in Rated Battlegrounds + SPELL_ATTR9_UNK15 = 0x00008000, // 15 + SPELL_ATTR9_UNK16 = 0x00010000, // 16 + SPELL_ATTR9_UNK17 = 0x00020000, // 17 + SPELL_ATTR9_UNK18 = 0x00040000, // 18 + SPELL_ATTR9_UNK19 = 0x00080000, // 19 + SPELL_ATTR9_UNK20 = 0x00100000, // 20 + SPELL_ATTR9_UNK21 = 0x00200000, // 21 + SPELL_ATTR9_UNK22 = 0x00400000, // 22 + SPELL_ATTR9_UNK23 = 0x00800000, // 23 + SPELL_ATTR9_UNK24 = 0x01000000, // 24 + SPELL_ATTR9_UNK25 = 0x02000000, // 25 + SPELL_ATTR9_UNK26 = 0x04000000, // 26 + SPELL_ATTR9_UNK27 = 0x08000000, // 27 + SPELL_ATTR9_UNK28 = 0x10000000, // 28 + SPELL_ATTR9_UNK29 = 0x20000000, // 29 + SPELL_ATTR9_UNK30 = 0x40000000, // 30 + SPELL_ATTR9_UNK31 = 0x80000000 // 31 +}; + +enum SpellAttr10 +{ + SPELL_ATTR10_UNK0 = 0x00000001, // 0 + SPELL_ATTR10_UNK1 = 0x00000002, // 1 + SPELL_ATTR10_UNK2 = 0x00000004, // 2 + SPELL_ATTR10_UNK3 = 0x00000008, // 3 + SPELL_ATTR10_WATER_SPOUT = 0x00000010, // 4 + SPELL_ATTR10_UNK5 = 0x00000020, // 5 + SPELL_ATTR10_UNK6 = 0x00000040, // 6 + SPELL_ATTR10_TELEPORT_PLAYER = 0x00000080, // 7 4 Teleport Player spells + SPELL_ATTR10_UNK8 = 0x00000100, // 8 + SPELL_ATTR10_UNK9 = 0x00000200, // 9 + SPELL_ATTR10_UNK10 = 0x00000400, // 10 + SPELL_ATTR10_HERB_GATHERING_MINING = 0x00000800, // 11 Only Herb Gathering and Mining + SPELL_ATTR10_UNK12 = 0x00001000, // 12 + SPELL_ATTR10_UNK13 = 0x00002000, // 13 + SPELL_ATTR10_UNK14 = 0x00004000, // 14 + SPELL_ATTR10_UNK15 = 0x00008000, // 15 + SPELL_ATTR10_UNK16 = 0x00010000, // 16 + SPELL_ATTR10_UNK17 = 0x00020000, // 17 + SPELL_ATTR10_UNK18 = 0x00040000, // 18 + SPELL_ATTR10_UNK19 = 0x00080000, // 19 + SPELL_ATTR10_UNK20 = 0x00100000, // 20 + SPELL_ATTR10_UNK21 = 0x00200000, // 21 + SPELL_ATTR10_UNK22 = 0x00400000, // 22 + SPELL_ATTR10_UNK23 = 0x00800000, // 23 + SPELL_ATTR10_UNK24 = 0x01000000, // 24 + SPELL_ATTR10_UNK25 = 0x02000000, // 25 + SPELL_ATTR10_UNK26 = 0x04000000, // 26 + SPELL_ATTR10_UNK27 = 0x08000000, // 27 + SPELL_ATTR10_UNK28 = 0x10000000, // 28 + SPELL_ATTR10_UNK29 = 0x20000000, // 29 + SPELL_ATTR10_UNK30 = 0x40000000, // 30 + SPELL_ATTR10_UNK31 = 0x80000000 // 31 +}; + #define MIN_TALENT_SPEC 0 #define MAX_TALENT_SPEC 1 #define MIN_TALENT_SPECS 1 #define MAX_TALENT_SPECS 2 -#define MAX_GLYPH_SLOT_INDEX 6 +#define MAX_GLYPH_SLOT_INDEX 9 +#define REQ_PRIMARY_TREE_TALENTS 31 // Custom values enum SpellClickUserTypes @@ -643,10 +761,12 @@ enum Language LANG_ZOMBIE = 36, LANG_GNOMISH_BINARY = 37, LANG_GOBLIN_BINARY = 38, + LANG_WORGEN = 39, + LANG_GOBLIN = 40, LANG_ADDON = 0xFFFFFFFF // used by addons, in 2.4.0 not exist, replaced by messagetype? }; -#define LANGUAGES_COUNT 19 +#define LANGUAGES_COUNT 21 enum TeamId { @@ -672,7 +792,7 @@ enum SpellEffects SPELL_EFFECT_INSTAKILL = 1, SPELL_EFFECT_SCHOOL_DAMAGE = 2, SPELL_EFFECT_DUMMY = 3, - SPELL_EFFECT_PORTAL_TELEPORT = 4, + SPELL_EFFECT_PORTAL_TELEPORT = 4, // Unused (4.3.4) SPELL_EFFECT_TELEPORT_UNITS = 5, SPELL_EFFECT_APPLY_AURA = 6, SPELL_EFFECT_ENVIRONMENTAL_DAMAGE = 7, @@ -681,9 +801,9 @@ enum SpellEffects SPELL_EFFECT_HEAL = 10, SPELL_EFFECT_BIND = 11, SPELL_EFFECT_PORTAL = 12, - SPELL_EFFECT_RITUAL_BASE = 13, - SPELL_EFFECT_RITUAL_SPECIALIZE = 14, - SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL = 15, + SPELL_EFFECT_RITUAL_BASE = 13, // Unused (4.3.4) + SPELL_EFFECT_RITUAL_SPECIALIZE = 14, // Unused (4.3.4) + SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL = 15, // Unused (4.3.4) SPELL_EFFECT_QUEST_COMPLETE = 16, SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL = 17, SPELL_EFFECT_RESURRECT = 18, @@ -713,14 +833,14 @@ enum SpellEffects SPELL_EFFECT_JUMP_DEST = 42, SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER = 43, SPELL_EFFECT_SKILL_STEP = 44, - SPELL_EFFECT_ADD_HONOR = 45, + SPELL_EFFECT_PLAY_MOVIE = 45, SPELL_EFFECT_SPAWN = 46, SPELL_EFFECT_TRADE_SKILL = 47, SPELL_EFFECT_STEALTH = 48, SPELL_EFFECT_DETECT = 49, SPELL_EFFECT_TRANS_DOOR = 50, - SPELL_EFFECT_FORCE_CRITICAL_HIT = 51, - SPELL_EFFECT_GUARANTEE_HIT = 52, + SPELL_EFFECT_FORCE_CRITICAL_HIT = 51, // Unused (4.3.4) + SPELL_EFFECT_GUARANTEE_HIT = 52, // Unused (4.3.4) SPELL_EFFECT_ENCHANT_ITEM = 53, SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY = 54, SPELL_EFFECT_TAMECREATURE = 55, @@ -790,7 +910,7 @@ enum SpellEffects SPELL_EFFECT_APPLY_AREA_AURA_PET = 119, SPELL_EFFECT_TELEPORT_GRAVEYARD = 120, SPELL_EFFECT_NORMALIZED_WEAPON_DMG = 121, - SPELL_EFFECT_122 = 122, + SPELL_EFFECT_122 = 122, // Unused (4.3.4) SPELL_EFFECT_SEND_TAXI = 123, SPELL_EFFECT_PULL_TOWARDS = 124, SPELL_EFFECT_MODIFY_THREAT_PERCENT = 125, @@ -831,203 +951,236 @@ enum SpellEffects SPELL_EFFECT_160 = 160, SPELL_EFFECT_TALENT_SPEC_COUNT = 161, SPELL_EFFECT_TALENT_SPEC_SELECT = 162, - SPELL_EFFECT_163 = 163, + SPELL_EFFECT_163 = 163, // Unused (4.3.4) SPELL_EFFECT_REMOVE_AURA = 164, - TOTAL_SPELL_EFFECTS = 165 + SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT = 165, + SPELL_EFFECT_GIVE_CURRENCY = 166, + SPELL_EFFECT_167 = 167, + SPELL_EFFECT_168 = 168, + SPELL_EFFECT_DESTROY_ITEM = 169, + SPELL_EFFECT_170 = 170, + SPELL_EFFECT_171 = 171, // Summons gamebject + SPELL_EFFECT_RESURRECT_WITH_AURA = 172, + SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB = 173, // Guild tab unlocked (guild perk) + SPELL_EFFECT_174 = 174, + SPELL_EFFECT_175 = 175, // Unused (4.3.4) + SPELL_EFFECT_176 = 176, // Some kind of sanctuary effect (Vanish) + SPELL_EFFECT_177 = 177, + SPELL_EFFECT_178 = 178, // Unused (4.3.4) + SPELL_EFFECT_CREATE_AREATRIGGER = 179, + SPELL_EFFECT_180 = 180, // Unused (4.3.4) + SPELL_EFFECT_181 = 181, // Unused (4.3.4) + SPELL_EFFECT_182 = 182, + TOTAL_SPELL_EFFECTS = 183, }; enum SpellCastResult { - SPELL_FAILED_SUCCESS = 0, - SPELL_FAILED_AFFECTING_COMBAT = 1, - SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 2, - SPELL_FAILED_ALREADY_AT_FULL_MANA = 3, - SPELL_FAILED_ALREADY_AT_FULL_POWER = 4, - SPELL_FAILED_ALREADY_BEING_TAMED = 5, - SPELL_FAILED_ALREADY_HAVE_CHARM = 6, - SPELL_FAILED_ALREADY_HAVE_SUMMON = 7, - SPELL_FAILED_ALREADY_OPEN = 8, - SPELL_FAILED_AURA_BOUNCED = 9, - SPELL_FAILED_AUTOTRACK_INTERRUPTED = 10, - SPELL_FAILED_BAD_IMPLICIT_TARGETS = 11, - SPELL_FAILED_BAD_TARGETS = 12, - SPELL_FAILED_CANT_BE_CHARMED = 13, - SPELL_FAILED_CANT_BE_DISENCHANTED = 14, - SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 15, - SPELL_FAILED_CANT_BE_MILLED = 16, - SPELL_FAILED_CANT_BE_PROSPECTED = 17, - SPELL_FAILED_CANT_CAST_ON_TAPPED = 18, - SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 19, - SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 20, - SPELL_FAILED_CANT_STEALTH = 21, - SPELL_FAILED_CASTER_AURASTATE = 22, - SPELL_FAILED_CASTER_DEAD = 23, - SPELL_FAILED_CHARMED = 24, - SPELL_FAILED_CHEST_IN_USE = 25, - SPELL_FAILED_CONFUSED = 26, - SPELL_FAILED_DONT_REPORT = 27, - SPELL_FAILED_EQUIPPED_ITEM = 28, - SPELL_FAILED_EQUIPPED_ITEM_CLASS = 29, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 30, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 31, - SPELL_FAILED_ERROR = 32, - SPELL_FAILED_FIZZLE = 33, - SPELL_FAILED_FLEEING = 34, - SPELL_FAILED_FOOD_LOWLEVEL = 35, - SPELL_FAILED_HIGHLEVEL = 36, - SPELL_FAILED_HUNGER_SATIATED = 37, - SPELL_FAILED_IMMUNE = 38, - SPELL_FAILED_INCORRECT_AREA = 39, - SPELL_FAILED_INTERRUPTED = 40, - SPELL_FAILED_INTERRUPTED_COMBAT = 41, - SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 42, - SPELL_FAILED_ITEM_GONE = 43, - SPELL_FAILED_ITEM_NOT_FOUND = 44, - SPELL_FAILED_ITEM_NOT_READY = 45, - SPELL_FAILED_LEVEL_REQUIREMENT = 46, - SPELL_FAILED_LINE_OF_SIGHT = 47, - SPELL_FAILED_LOWLEVEL = 48, - SPELL_FAILED_LOW_CASTLEVEL = 49, - SPELL_FAILED_MAINHAND_EMPTY = 50, - SPELL_FAILED_MOVING = 51, - SPELL_FAILED_NEED_AMMO = 52, - SPELL_FAILED_NEED_AMMO_POUCH = 53, - SPELL_FAILED_NEED_EXOTIC_AMMO = 54, - SPELL_FAILED_NEED_MORE_ITEMS = 55, - SPELL_FAILED_NOPATH = 56, - SPELL_FAILED_NOT_BEHIND = 57, - SPELL_FAILED_NOT_FISHABLE = 58, - SPELL_FAILED_NOT_FLYING = 59, - SPELL_FAILED_NOT_HERE = 60, - SPELL_FAILED_NOT_INFRONT = 61, - SPELL_FAILED_NOT_IN_CONTROL = 62, - SPELL_FAILED_NOT_KNOWN = 63, - SPELL_FAILED_NOT_MOUNTED = 64, - SPELL_FAILED_NOT_ON_TAXI = 65, - SPELL_FAILED_NOT_ON_TRANSPORT = 66, - SPELL_FAILED_NOT_READY = 67, - SPELL_FAILED_NOT_SHAPESHIFT = 68, - SPELL_FAILED_NOT_STANDING = 69, - SPELL_FAILED_NOT_TRADEABLE = 70, - SPELL_FAILED_NOT_TRADING = 71, - SPELL_FAILED_NOT_UNSHEATHED = 72, - SPELL_FAILED_NOT_WHILE_GHOST = 73, - SPELL_FAILED_NOT_WHILE_LOOTING = 74, - SPELL_FAILED_NO_AMMO = 75, - SPELL_FAILED_NO_CHARGES_REMAIN = 76, - SPELL_FAILED_NO_CHAMPION = 77, - SPELL_FAILED_NO_COMBO_POINTS = 78, - SPELL_FAILED_NO_DUELING = 79, - SPELL_FAILED_NO_ENDURANCE = 80, - SPELL_FAILED_NO_FISH = 81, - SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 82, - SPELL_FAILED_NO_MOUNTS_ALLOWED = 83, - SPELL_FAILED_NO_PET = 84, - SPELL_FAILED_NO_POWER = 85, - SPELL_FAILED_NOTHING_TO_DISPEL = 86, - SPELL_FAILED_NOTHING_TO_STEAL = 87, - SPELL_FAILED_ONLY_ABOVEWATER = 88, - SPELL_FAILED_ONLY_DAYTIME = 89, - SPELL_FAILED_ONLY_INDOORS = 90, - SPELL_FAILED_ONLY_MOUNTED = 91, - SPELL_FAILED_ONLY_NIGHTTIME = 92, - SPELL_FAILED_ONLY_OUTDOORS = 93, - SPELL_FAILED_ONLY_SHAPESHIFT = 94, - SPELL_FAILED_ONLY_STEALTHED = 95, - SPELL_FAILED_ONLY_UNDERWATER = 96, - SPELL_FAILED_OUT_OF_RANGE = 97, - SPELL_FAILED_PACIFIED = 98, - SPELL_FAILED_POSSESSED = 99, - SPELL_FAILED_REAGENTS = 100, - SPELL_FAILED_REQUIRES_AREA = 101, - SPELL_FAILED_REQUIRES_SPELL_FOCUS = 102, - SPELL_FAILED_ROOTED = 103, - SPELL_FAILED_SILENCED = 104, - SPELL_FAILED_SPELL_IN_PROGRESS = 105, - SPELL_FAILED_SPELL_LEARNED = 106, - SPELL_FAILED_SPELL_UNAVAILABLE = 107, - SPELL_FAILED_STUNNED = 108, - SPELL_FAILED_TARGETS_DEAD = 109, - SPELL_FAILED_TARGET_AFFECTING_COMBAT = 110, - SPELL_FAILED_TARGET_AURASTATE = 111, - SPELL_FAILED_TARGET_DUELING = 112, - SPELL_FAILED_TARGET_ENEMY = 113, - SPELL_FAILED_TARGET_ENRAGED = 114, - SPELL_FAILED_TARGET_FRIENDLY = 115, - SPELL_FAILED_TARGET_IN_COMBAT = 116, - SPELL_FAILED_TARGET_IS_PLAYER = 117, - SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 118, - SPELL_FAILED_TARGET_NOT_DEAD = 119, - SPELL_FAILED_TARGET_NOT_IN_PARTY = 120, - SPELL_FAILED_TARGET_NOT_LOOTED = 121, - SPELL_FAILED_TARGET_NOT_PLAYER = 122, - SPELL_FAILED_TARGET_NO_POCKETS = 123, - SPELL_FAILED_TARGET_NO_WEAPONS = 124, - SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 125, - SPELL_FAILED_TARGET_UNSKINNABLE = 126, - SPELL_FAILED_THIRST_SATIATED = 127, - SPELL_FAILED_TOO_CLOSE = 128, - SPELL_FAILED_TOO_MANY_OF_ITEM = 129, - SPELL_FAILED_TOTEM_CATEGORY = 130, - SPELL_FAILED_TOTEMS = 131, - SPELL_FAILED_TRY_AGAIN = 132, - SPELL_FAILED_UNIT_NOT_BEHIND = 133, - SPELL_FAILED_UNIT_NOT_INFRONT = 134, - SPELL_FAILED_WRONG_PET_FOOD = 135, - SPELL_FAILED_NOT_WHILE_FATIGUED = 136, - SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 137, - SPELL_FAILED_NOT_WHILE_TRADING = 138, - SPELL_FAILED_TARGET_NOT_IN_RAID = 139, - SPELL_FAILED_TARGET_FREEFORALL = 140, - SPELL_FAILED_NO_EDIBLE_CORPSES = 141, - SPELL_FAILED_ONLY_BATTLEGROUNDS = 142, - SPELL_FAILED_TARGET_NOT_GHOST = 143, - SPELL_FAILED_TRANSFORM_UNUSABLE = 144, - SPELL_FAILED_WRONG_WEATHER = 145, - SPELL_FAILED_DAMAGE_IMMUNE = 146, - SPELL_FAILED_PREVENTED_BY_MECHANIC = 147, - SPELL_FAILED_PLAY_TIME = 148, - SPELL_FAILED_REPUTATION = 149, - SPELL_FAILED_MIN_SKILL = 150, - SPELL_FAILED_NOT_IN_ARENA = 151, - SPELL_FAILED_NOT_ON_SHAPESHIFT = 152, - SPELL_FAILED_NOT_ON_STEALTHED = 153, - SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 154, - SPELL_FAILED_NOT_ON_MOUNTED = 155, - SPELL_FAILED_TOO_SHALLOW = 156, - SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 157, - SPELL_FAILED_TARGET_IS_TRIVIAL = 158, - SPELL_FAILED_BM_OR_INVISGOD = 159, - SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 160, - SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 161, - SPELL_FAILED_NOT_IDLE = 162, - SPELL_FAILED_NOT_INACTIVE = 163, - SPELL_FAILED_PARTIAL_PLAYTIME = 164, - SPELL_FAILED_NO_PLAYTIME = 165, - SPELL_FAILED_NOT_IN_BATTLEGROUND = 166, - SPELL_FAILED_NOT_IN_RAID_INSTANCE = 167, - SPELL_FAILED_ONLY_IN_ARENA = 168, - SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 169, - SPELL_FAILED_ON_USE_ENCHANT = 170, - SPELL_FAILED_NOT_ON_GROUND = 171, - SPELL_FAILED_CUSTOM_ERROR = 172, - SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 173, - SPELL_FAILED_TOO_MANY_SOCKETS = 174, - SPELL_FAILED_INVALID_GLYPH = 175, - SPELL_FAILED_UNIQUE_GLYPH = 176, - SPELL_FAILED_GLYPH_SOCKET_LOCKED = 177, - SPELL_FAILED_NO_VALID_TARGETS = 178, - SPELL_FAILED_ITEM_AT_MAX_CHARGES = 179, - SPELL_FAILED_NOT_IN_BARBERSHOP = 180, - SPELL_FAILED_FISHING_TOO_LOW = 181, - SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 182, - SPELL_FAILED_SUMMON_PENDING = 183, - SPELL_FAILED_MAX_SOCKETS = 184, - SPELL_FAILED_PET_CAN_RENAME = 185, - SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED = 186, - SPELL_FAILED_UNKNOWN = 187, // actually doesn't exist in client - - SPELL_CAST_OK = 255 // custom value, must not be sent to client + SPELL_FAILED_SUCCESS = 0, + SPELL_FAILED_AFFECTING_COMBAT = 1, + SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 2, + SPELL_FAILED_ALREADY_AT_FULL_MANA = 3, + SPELL_FAILED_ALREADY_AT_FULL_POWER = 4, + SPELL_FAILED_ALREADY_BEING_TAMED = 5, + SPELL_FAILED_ALREADY_HAVE_CHARM = 6, + SPELL_FAILED_ALREADY_HAVE_SUMMON = 7, + SPELL_FAILED_ALREADY_HAVE_PET = 8, + SPELL_FAILED_ALREADY_OPEN = 9, + SPELL_FAILED_AURA_BOUNCED = 10, + SPELL_FAILED_AUTOTRACK_INTERRUPTED = 11, + SPELL_FAILED_BAD_IMPLICIT_TARGETS = 12, + SPELL_FAILED_BAD_TARGETS = 13, + SPELL_FAILED_CANT_BE_CHARMED = 14, + SPELL_FAILED_CANT_BE_DISENCHANTED = 15, + SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 16, + SPELL_FAILED_CANT_BE_MILLED = 17, + SPELL_FAILED_CANT_BE_PROSPECTED = 18, + SPELL_FAILED_CANT_CAST_ON_TAPPED = 19, + SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 20, + SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 21, + SPELL_FAILED_CANT_STEALTH = 22, + SPELL_FAILED_CASTER_AURASTATE = 23, + SPELL_FAILED_CASTER_DEAD = 24, + SPELL_FAILED_CHARMED = 25, + SPELL_FAILED_CHEST_IN_USE = 26, + SPELL_FAILED_CONFUSED = 27, + SPELL_FAILED_DONT_REPORT = 28, + SPELL_FAILED_EQUIPPED_ITEM = 29, + SPELL_FAILED_EQUIPPED_ITEM_CLASS = 30, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 31, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 32, + SPELL_FAILED_ERROR = 33, + SPELL_FAILED_FALLING = 34, + SPELL_FAILED_FIZZLE = 35, + SPELL_FAILED_FLEEING = 36, + SPELL_FAILED_FOOD_LOWLEVEL = 37, + SPELL_FAILED_HIGHLEVEL = 38, + SPELL_FAILED_HUNGER_SATIATED = 39, + SPELL_FAILED_IMMUNE = 40, + SPELL_FAILED_INCORRECT_AREA = 41, + SPELL_FAILED_INTERRUPTED = 42, + SPELL_FAILED_INTERRUPTED_COMBAT = 43, + SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 44, + SPELL_FAILED_ITEM_GONE = 45, + SPELL_FAILED_ITEM_NOT_FOUND = 46, + SPELL_FAILED_ITEM_NOT_READY = 47, + SPELL_FAILED_LEVEL_REQUIREMENT = 48, + SPELL_FAILED_LINE_OF_SIGHT = 49, + SPELL_FAILED_LOWLEVEL = 50, + SPELL_FAILED_LOW_CASTLEVEL = 51, + SPELL_FAILED_MAINHAND_EMPTY = 52, + SPELL_FAILED_MOVING = 53, + SPELL_FAILED_NEED_AMMO = 54, + SPELL_FAILED_NEED_AMMO_POUCH = 55, + SPELL_FAILED_NEED_EXOTIC_AMMO = 56, + SPELL_FAILED_NEED_MORE_ITEMS = 57, + SPELL_FAILED_NOPATH = 58, + SPELL_FAILED_NOT_BEHIND = 59, + SPELL_FAILED_NOT_FISHABLE = 60, + SPELL_FAILED_NOT_FLYING = 61, + SPELL_FAILED_NOT_HERE = 62, + SPELL_FAILED_NOT_INFRONT = 63, + SPELL_FAILED_NOT_IN_CONTROL = 64, + SPELL_FAILED_NOT_KNOWN = 65, + SPELL_FAILED_NOT_MOUNTED = 66, + SPELL_FAILED_NOT_ON_TAXI = 67, + SPELL_FAILED_NOT_ON_TRANSPORT = 68, + SPELL_FAILED_NOT_READY = 69, + SPELL_FAILED_NOT_SHAPESHIFT = 70, + SPELL_FAILED_NOT_STANDING = 71, + SPELL_FAILED_NOT_TRADEABLE = 72, + SPELL_FAILED_NOT_TRADING = 73, + SPELL_FAILED_NOT_UNSHEATHED = 74, + SPELL_FAILED_NOT_WHILE_GHOST = 75, + SPELL_FAILED_NOT_WHILE_LOOTING = 76, + SPELL_FAILED_NO_AMMO = 77, + SPELL_FAILED_NO_CHARGES_REMAIN = 78, + SPELL_FAILED_NO_CHAMPION = 79, + SPELL_FAILED_NO_COMBO_POINTS = 80, + SPELL_FAILED_NO_DUELING = 81, + SPELL_FAILED_NO_ENDURANCE = 82, + SPELL_FAILED_NO_FISH = 83, + SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 84, + SPELL_FAILED_NO_MOUNTS_ALLOWED = 85, + SPELL_FAILED_NO_PET = 86, + SPELL_FAILED_NO_POWER = 87, + SPELL_FAILED_NOTHING_TO_DISPEL = 88, + SPELL_FAILED_NOTHING_TO_STEAL = 89, + SPELL_FAILED_ONLY_ABOVEWATER = 90, + SPELL_FAILED_ONLY_DAYTIME = 91, + SPELL_FAILED_ONLY_INDOORS = 92, + SPELL_FAILED_ONLY_MOUNTED = 93, + SPELL_FAILED_ONLY_NIGHTTIME = 94, + SPELL_FAILED_ONLY_OUTDOORS = 95, + SPELL_FAILED_ONLY_SHAPESHIFT = 96, + SPELL_FAILED_ONLY_STEALTHED = 97, + SPELL_FAILED_ONLY_UNDERWATER = 98, + SPELL_FAILED_OUT_OF_RANGE = 99, + SPELL_FAILED_PACIFIED = 100, + SPELL_FAILED_POSSESSED = 101, + SPELL_FAILED_REAGENTS = 102, + SPELL_FAILED_REQUIRES_AREA = 103, + SPELL_FAILED_REQUIRES_SPELL_FOCUS = 104, + SPELL_FAILED_ROOTED = 105, + SPELL_FAILED_SILENCED = 106, + SPELL_FAILED_SPELL_IN_PROGRESS = 107, + SPELL_FAILED_SPELL_LEARNED = 108, + SPELL_FAILED_SPELL_UNAVAILABLE = 109, + SPELL_FAILED_STUNNED = 110, + SPELL_FAILED_TARGETS_DEAD = 111, + SPELL_FAILED_TARGET_AFFECTING_COMBAT = 112, + SPELL_FAILED_TARGET_AURASTATE = 113, + SPELL_FAILED_TARGET_DUELING = 114, + SPELL_FAILED_TARGET_ENEMY = 115, + SPELL_FAILED_TARGET_ENRAGED = 116, + SPELL_FAILED_TARGET_FRIENDLY = 117, + SPELL_FAILED_TARGET_IN_COMBAT = 118, + SPELL_FAILED_TARGET_IS_PLAYER = 119, + SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 120, + SPELL_FAILED_TARGET_NOT_DEAD = 121, + SPELL_FAILED_TARGET_NOT_IN_PARTY = 122, + SPELL_FAILED_TARGET_NOT_LOOTED = 123, + SPELL_FAILED_TARGET_NOT_PLAYER = 124, + SPELL_FAILED_TARGET_NO_POCKETS = 125, + SPELL_FAILED_TARGET_NO_WEAPONS = 126, + SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 127, + SPELL_FAILED_TARGET_UNSKINNABLE = 128, + SPELL_FAILED_THIRST_SATIATED = 129, + SPELL_FAILED_TOO_CLOSE = 130, + SPELL_FAILED_TOO_MANY_OF_ITEM = 131, + SPELL_FAILED_TOTEM_CATEGORY = 132, + SPELL_FAILED_TOTEMS = 133, + SPELL_FAILED_TRY_AGAIN = 134, + SPELL_FAILED_UNIT_NOT_BEHIND = 135, + SPELL_FAILED_UNIT_NOT_INFRONT = 136, + SPELL_FAILED_VISION_OBSCURED = 137, + SPELL_FAILED_WRONG_PET_FOOD = 138, + SPELL_FAILED_NOT_WHILE_FATIGUED = 139, + SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 140, + SPELL_FAILED_NOT_WHILE_TRADING = 141, + SPELL_FAILED_TARGET_NOT_IN_RAID = 142, + SPELL_FAILED_TARGET_FREEFORALL = 143, + SPELL_FAILED_NO_EDIBLE_CORPSES = 144, + SPELL_FAILED_ONLY_BATTLEGROUNDS = 145, + SPELL_FAILED_TARGET_NOT_GHOST = 146, + SPELL_FAILED_TRANSFORM_UNUSABLE = 147, + SPELL_FAILED_WRONG_WEATHER = 148, + SPELL_FAILED_DAMAGE_IMMUNE = 149, + SPELL_FAILED_PREVENTED_BY_MECHANIC = 150, + SPELL_FAILED_PLAY_TIME = 151, + SPELL_FAILED_REPUTATION = 152, + SPELL_FAILED_MIN_SKILL = 153, + SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND = 154, + SPELL_FAILED_NOT_ON_SHAPESHIFT = 155, + SPELL_FAILED_NOT_ON_STEALTHED = 156, + SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 157, + SPELL_FAILED_NOT_ON_MOUNTED = 158, + SPELL_FAILED_TOO_SHALLOW = 159, + SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 160, + SPELL_FAILED_TARGET_IS_TRIVIAL = 161, + SPELL_FAILED_BM_OR_INVISGOD = 162, + SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 163, + SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 164, + SPELL_FAILED_NOT_IDLE = 165, + SPELL_FAILED_NOT_INACTIVE = 166, + SPELL_FAILED_PARTIAL_PLAYTIME = 167, + SPELL_FAILED_NO_PLAYTIME = 168, + SPELL_FAILED_NOT_IN_BATTLEGROUND = 169, + SPELL_FAILED_NOT_IN_RAID_INSTANCE = 170, + SPELL_FAILED_ONLY_IN_ARENA = 171, + SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 172, + SPELL_FAILED_ON_USE_ENCHANT = 173, + SPELL_FAILED_NOT_ON_GROUND = 174, + SPELL_FAILED_CUSTOM_ERROR = 175, + SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 176, + SPELL_FAILED_TOO_MANY_SOCKETS = 177, + SPELL_FAILED_INVALID_GLYPH = 178, + SPELL_FAILED_UNIQUE_GLYPH = 179, + SPELL_FAILED_GLYPH_SOCKET_LOCKED = 180, + SPELL_FAILED_NO_VALID_TARGETS = 181, + SPELL_FAILED_ITEM_AT_MAX_CHARGES = 182, + SPELL_FAILED_NOT_IN_BARBERSHOP = 183, + SPELL_FAILED_FISHING_TOO_LOW = 184, + SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 185, + SPELL_FAILED_SUMMON_PENDING = 186, + SPELL_FAILED_MAX_SOCKETS = 187, + SPELL_FAILED_PET_CAN_RENAME = 188, + SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED = 189, + SPELL_FAILED_NO_ACTIONS = 190, + SPELL_FAILED_CURRENCY_WEIGHT_MISMATCH = 191, + SPELL_FAILED_WEIGHT_NOT_ENOUGH = 192, + SPELL_FAILED_WEIGHT_TOO_MUCH = 193, + SPELL_FAILED_NO_VACANT_SEAT = 194, + SPELL_FAILED_NO_LIQUID = 195, + SPELL_FAILED_ONLY_NOT_SWIMMING = 196, + SPELL_FAILED_BY_NOT_MOVING = 197, + SPELL_FAILED_IN_COMBAT_RES_LIMIT_REACHED = 198, + SPELL_FAILED_NOT_IN_ARENA = 199, + SPELL_FAILED_TARGET_NOT_GROUNDED = 200, + SPELL_FAILED_EXCEEDED_WEEKLY_USAGE = 201, + SPELL_FAILED_NOT_IN_LFG_DUNGEON = 202, + SPELL_FAILED_UNKNOWN = 254, // custom value, default case + SPELL_CAST_OK = 255, // custom value, must not be sent to client }; enum SpellCustomErrors @@ -1100,38 +1253,80 @@ enum SpellCustomErrors SPELL_CUSTOM_ERROR_GM_ONLY = 65, // Only GMs may use that. Your account has been reported for investigation. SPELL_CUSTOM_ERROR_REQUIRES_LEVEL_58 = 66, // You must reach level 58 to use this portal. SPELL_CUSTOM_ERROR_AT_HONOR_CAP = 67, // You already have the maximum amount of honor. - SPELL_CUSTOM_ERROR_68 = 68, // "" - SPELL_CUSTOM_ERROR_69 = 69, // "" - SPELL_CUSTOM_ERROR_70 = 70, // "" - SPELL_CUSTOM_ERROR_71 = 71, // "" - SPELL_CUSTOM_ERROR_72 = 72, // "" - SPELL_CUSTOM_ERROR_73 = 73, // "" - SPELL_CUSTOM_ERROR_74 = 74, // "" + SPELL_CUSTOM_ERROR_HAVE_HOT_ROD = 68, // You already have a Hot Rod. + SPELL_CUSTOM_ERROR_PARTYGOER_MORE_BUBBLY = 69, // This partygoer wants some more bubbly + SPELL_CUSTOM_ERROR_PARTYGOER_NEED_BUCKET = 70, // This partygoer needs a bucket! + SPELL_CUSTOM_ERROR_PARTYGOER_WANT_TO_DANCE = 71, // This partygoer wants to dance with you. + SPELL_CUSTOM_ERROR_PARTYGOER_WANT_FIREWORKS = 72, // This partygoer wants to see some fireworks. + SPELL_CUSTOM_ERROR_PARTYGOER_WANT_APPETIZER = 73, // This partygoer wants some more hors d'oeuvres. + SPELL_CUSTOM_ERROR_GOBLIN_BATTERY_DEPLETED = 74, // The Goblin All-In-1-Der Belt's battery is depleted. SPELL_CUSTOM_ERROR_MUST_HAVE_DEMONIC_CIRCLE = 75, // You must have a demonic circle active. SPELL_CUSTOM_ERROR_AT_MAX_RAGE = 76, // You already have maximum rage SPELL_CUSTOM_ERROR_REQUIRES_350_ENGINEERING = 77, // Requires Engineering (350) SPELL_CUSTOM_ERROR_SOUL_BELONGS_TO_LICH_KING = 78, // Your soul belongs to the Lich King SPELL_CUSTOM_ERROR_ATTENDANT_HAS_PONY = 79, // Your attendant already has an Argent Pony - SPELL_CUSTOM_ERROR_80 = 80, // "" - SPELL_CUSTOM_ERROR_81 = 81, // "" - SPELL_CUSTOM_ERROR_82 = 82, // "" + SPELL_CUSTOM_ERROR_GOBLIN_STARTING_MISSION = 80, // First, Overload the Defective Generator, Activate the Leaky Stove, and Drop a Cigar on the Flammable Bed. + SPELL_CUSTOM_ERROR_GASBOT_ALREADY_SENT = 81, // You've already sent in the Gasbot and destroyed headquarters! + SPELL_CUSTOM_ERROR_GOBLIN_IS_PARTIED_OUT = 82, // This goblin is all partied out! SPELL_CUSTOM_ERROR_MUST_HAVE_FIRE_TOTEM = 83, // You must have a Fire Totem active. SPELL_CUSTOM_ERROR_CANT_TARGET_VAMPIRES = 84, // You may not bite other vampires. SPELL_CUSTOM_ERROR_PET_ALREADY_AT_YOUR_LEVEL = 85, // Your pet is already at your level. SPELL_CUSTOM_ERROR_MISSING_ITEM_REQUIREMENS = 86, // You do not meet the level requirements for this item. SPELL_CUSTOM_ERROR_TOO_MANY_ABOMINATIONS = 87, // There are too many Mutated Abominations. SPELL_CUSTOM_ERROR_ALL_POTIONS_USED = 88, // The potions have all been depleted by Professor Putricide. - SPELL_CUSTOM_ERROR_89 = 89, // "" + SPELL_CUSTOM_ERROR_DEFEATED_ENOUGH_ALREADY = 89, // You have already defeated enough of them. SPELL_CUSTOM_ERROR_REQUIRES_LEVEL_65 = 90, // Requires level 65 - SPELL_CUSTOM_ERROR_91 = 91, // "" - SPELL_CUSTOM_ERROR_92 = 92, // "" - SPELL_CUSTOM_ERROR_93 = 93, // "" - SPELL_CUSTOM_ERROR_94 = 94, // "" - SPELL_CUSTOM_ERROR_95 = 95, // "" + SPELL_CUSTOM_ERROR_DESTROYED_KTC_OIL_PLATFORM = 91, // You have already destroyed the KTC Oil Platform. + SPELL_CUSTOM_ERROR_LAUNCHED_ENOUGH_CAGES = 92, // You have already launched enough cages. + SPELL_CUSTOM_ERROR_REQUIRES_BOOSTER_ROCKETS = 93, // Requires Single-Stage Booster Rockets. Return to Hobart Grapplehammer to get more. + SPELL_CUSTOM_ERROR_ENOUGH_WILD_CLUCKERS = 94, // You have already captured enough wild cluckers. + SPELL_CUSTOM_ERROR_REQUIRES_CONTROL_FIREWORKS = 95, // Requires Remote Control Fireworks. Return to Hobart Grapplehammer to get more. SPELL_CUSTOM_ERROR_MAX_NUMBER_OF_RECRUITS = 96, // You already have the max number of recruits. SPELL_CUSTOM_ERROR_MAX_NUMBER_OF_VOLUNTEERS = 97, // You already have the max number of volunteers. SPELL_CUSTOM_ERROR_FROSTMOURNE_RENDERED_RESURRECT = 98, // Frostmourne has rendered you unable to resurrect. - SPELL_CUSTOM_ERROR_CANT_MOUNT_WITH_SHAPESHIFT = 99 // You can't mount while affected by that shapeshift. + SPELL_CUSTOM_ERROR_CANT_MOUNT_WITH_SHAPESHIFT = 99, // You can't mount while affected by that shapeshift. + SPELL_CUSTOM_ERROR_FAWNS_ALREADY_FOLLOWING = 100, // Three fawns are already following you! + SPELL_CUSTOM_ERROR_ALREADY_HAVE_RIVER_BOAT = 101, // You already have a River Boat. + SPELL_CUSTOM_ERROR_NO_ACTIVE_ENCHANTMENT = 102, // You have no active enchantment to unleash. + SPELL_CUSTOM_ERROR_ENOUGH_HIGHBOURNE_SOULS = 103, // You have bound enough Highborne souls. Return to Arcanist Valdurian. + SPELL_CUSTOM_ERROR_ATLEAST_40YD_FROM_OIL_DRILLING = 104, // You must be at least 40 yards away from all other Oil Drilling Rigs. + SPELL_CUSTOM_ERROR_ABOVE_ENSLAVED_PEARL_MINER = 106, // You must be above the Enslaved Pearl Miner. + SPELL_CUSTOM_ERROR_MUST_TARGET_CORPSE_SPECIAL_1 = 107, // You must target the corpse of a Seabrush Terrapin, Scourgut Remora, or Spinescale Hammerhead. + SPELL_CUSTOM_ERROR_SLAGHAMMER_ALREADY_PRISONER = 108, // Ambassador Slaghammer is already your prisoner. + SPELL_CUSTOM_ERROR_REQUIRE_ATTUNED_LOCATION_1 = 109, // Requires a location that is attuned with the Naz'jar Battlemaiden. + SPELL_CUSTOM_ERROR_NEED_TO_FREE_DRAKE_FIRST = 110, // Free the Drake from the net first! + SPELL_CUSTOM_ERROR_DRAGONMAW_ALLIES_ALREADY_FOLLOW = 111, // You already have three Dragonmaw allies following you. + SPELL_CUSTOM_ERROR_REQUIRE_OPPOSABLE_THUMBS = 112, // Requires Opposable Thumbs. + SPELL_CUSTOM_ERROR_NOT_ENOUGH_HEALTH_2 = 113, // Not enough health + SPELL_CUSTOM_ERROR_ENOUGH_FORSAKEN_TROOPERS = 114, // You already have enough Forsaken Troopers. + SPELL_CUSTOM_ERROR_CANNOT_JUMP_TO_BOULDER = 115, // You cannot jump to another boulder yet. + SPELL_CUSTOM_ERROR_SKILL_TOO_HIGH = 116, // Skill too high. + SPELL_CUSTOM_ERROR_ALREADY_6_SURVIVORS_RESCUED = 117, // You have already rescued 6 Survivors. + SPELL_CUSTOM_ERROR_MUST_FACE_SHIPS_FROM_BALLOON = 118, // You need to be facing the ships from the rescue balloon. + SPELL_CUSTOM_ERROR_CANNOT_SUPERVISE_MORE_CULTISTS = 119, // You cannot supervise more than 5 Arrested Cultists at a time. + SPELL_CUSTOM_ERROR_REQUIRES_LEVEL_85 = 120, // You must reach level 85 to use this portal. + SPELL_CUSTOM_ERROR_MUST_BE_BELOW_35_HEALTH = 121, // Your target must be below 35% health. + SPELL_CUSTOM_ERROR_MUST_SELECT_TALENT_SPECIAL = 122, // You must select a talent specialization first. + SPELL_CUSTOM_ERROR_TOO_WISE_AND_POWERFUL = 123, // You are too wise and powerful to gain any benefit from that item. + SPELL_CUSTOM_ERROR_TOO_CLOSE_ARGENT_LIGHTWELL = 124, // You are within 10 yards of another Argent Lightwell. + SPELL_CUSTOM_ERROR_NOT_WHILE_SHAPESHIFTED = 125, // You can't do that while shapeshifted. + SPELL_CUSTOM_ERROR_MANA_GEM_IN_BANK = 126, // You already have a Mana Gem in your bank. + SPELL_CUSTOM_ERROR_FLAME_SHOCK_NOT_ACTIVE = 127, // You must have at least one Flame Shock active. + SPELL_CUSTOM_ERROR_CANT_TRANSFORM = 128, // You cannot transform right now + SPELL_CUSTOM_ERROR_PET_MUST_BE_ATTACKING = 129, // Your pet must be attacking a target. + SPELL_CUSTOM_ERROR_GNOMISH_ENGINEERING = 130, // Requires Gnomish Engineering + SPELL_CUSTOM_ERROR_GOBLIN_ENGINEERING = 131, // Requires Goblin Engineering + SPELL_CUSTOM_ERROR_NO_TARGET = 132, // You have no target. + SPELL_CUSTOM_ERROR_PET_OUT_OF_RANGE = 133, // Your Pet is out of range of the target. + SPELL_CUSTOM_ERROR_HOLDING_FLAG = 134, // You can't do that while holding the flag. + SPELL_CUSTOM_ERROR_TARGET_HOLDING_FLAG = 135, // You can't do that to targets holding the flag. + SPELL_CUSTOM_ERROR_PORTAL_NOT_OPEN = 136, // The portal is not yet open. Continue helping the druids at the Sanctuary of Malorne. + SPELL_CUSTOM_ERROR_AGGRA_AIR_TOTEM = 137, // You need to be closer to Aggra's Air Totem, in the west. + SPELL_CUSTOM_ERROR_AGGRA_WATER_TOTEM = 138, // You need to be closer to Aggra's Water Totem, in the north. + SPELL_CUSTOM_ERROR_AGGRA_EARTH_TOTEM = 139, // You need to be closer to Aggra's Earth Totem, in the east. + SPELL_CUSTOM_ERROR_AGGRA_FIRE_TOTEM = 140, // You need to be closer to Aggra's Fire Totem, near Thrall. + SPELL_CUSTOM_ERROR_TARGET_HAS_STARTDUST_2 = 148, // Target is already affected by Stardust No. 2. + SPELL_CUSTOM_ERROR_ELEMENTIUM_GEM_CLUSTERS = 149 // You cannot deconstruct Elementium Gem Clusters while collecting them! }; enum StealthType @@ -1156,8 +1351,34 @@ enum InvisibilityType INVISIBILITY_UNK9 = 9, INVISIBILITY_UNK10 = 10, INVISIBILITY_UNK11 = 11, - - TOTAL_INVISIBILITY_TYPES = 12 + INVISIBILITY_UNK12 = 12, + INVISIBILITY_TRA13 = 13, + INVISIBILITY_UNK14 = 14, + INVISIBILITY_UNK15 = 15, + INVISIBILITY_UNK16 = 16, + INVISIBILITY_UNK17 = 17, + INVISIBILITY_UNK18 = 18, + INVISIBILITY_UNK19 = 19, + INVISIBILITY_UNK20 = 20, + INVISIBILITY_UNK21 = 21, + INVISIBILITY_UNK22 = 22, + INVISIBILITY_TRA23 = 23, + INVISIBILITY_UNK24 = 24, + INVISIBILITY_UNK25 = 25, + INVISIBILITY_UNK26 = 26, + INVISIBILITY_UNK27 = 27, + INVISIBILITY_UNK28 = 28, + INVISIBILITY_UNK29 = 29, + INVISIBILITY_UNK30 = 30, + INVISIBILITY_UNK31 = 31, + INVISIBILITY_UNK32 = 32, + INVISIBILITY_UNK33 = 33, + INVISIBILITY_UNK34 = 34, + INVISIBILITY_UNK35 = 35, + INVISIBILITY_UNK36 = 36, + INVISIBILITY_UNK37 = 37, + + TOTAL_INVISIBILITY_TYPES = 38 }; enum ServerSideVisibilityType @@ -1243,14 +1464,15 @@ enum Mechanics MECHANIC_IMMUNE_SHIELD = 29, // Divine (Blessing) Shield/Protection and Ice Block MECHANIC_SAPPED = 30, MECHANIC_ENRAGED = 31, - MAX_MECHANIC = 32 + MECHANIC_WOUNDED = 32, + MAX_MECHANIC = 33 }; // Used for spell 42292 Immune Movement Impairment and Loss of Control (0x49967ca6) #define IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK (\ (1<<MECHANIC_CHARM)|(1<<MECHANIC_DISORIENTED)|(1<<MECHANIC_FEAR)| \ (1<<MECHANIC_ROOT)|(1<<MECHANIC_SLEEP)|(1<<MECHANIC_SNARE)| \ - (1<<MECHANIC_STUN)|(1<<MECHANIC_FREEZE)|(1<<MECHANIC_KNOCKOUT)| \ + (1<<MECHANIC_STUN)|(1<<MECHANIC_FREEZE)|(1<<MECHANIC_SILENCE)|(1<<MECHANIC_DISARM)|(1<<MECHANIC_KNOCKOUT)| \ (1<<MECHANIC_POLYMORPH)|(1<<MECHANIC_BANISH)|(1<<MECHANIC_SHACKLE)| \ (1<<MECHANIC_TURN)|(1<<MECHANIC_HORROR)|(1<<MECHANIC_DAZE)| \ (1<<MECHANIC_SAPPED)) @@ -1399,6 +1621,23 @@ enum Targets TARGET_UNK_DEST_AREA_UNK_107 = 107, // not enough info - only generic spells avalible TARGET_GAMEOBJECT_CONE = 108, TARGET_DEST_UNK_110 = 110, // 1 spell + TARGET_UNK_111 = 111, + TARGET_UNK_112 = 112, + TARGET_UNK_113 = 113, + TARGET_UNK_114 = 114, + TARGET_UNK_115 = 115, + TARGET_UNK_116 = 116, + TARGET_UNK_117 = 117, + TARGET_UNK_118 = 118, + TARGET_UNK_119 = 119, + TARGET_UNK_120 = 120, + TARGET_UNK_121 = 121, + TARGET_UNK_122 = 122, + TARGET_UNK_123 = 123, + TARGET_UNK_124 = 124, + TARGET_UNK_125 = 125, + TARGET_UNK_126 = 126, + TARGET_UNK_127 = 127, TOTAL_SPELL_TARGETS }; @@ -1440,7 +1679,8 @@ enum SpellPreventionType { SPELL_PREVENTION_TYPE_NONE = 0, SPELL_PREVENTION_TYPE_SILENCE = 1, - SPELL_PREVENTION_TYPE_PACIFY = 2 + SPELL_PREVENTION_TYPE_PACIFY = 2, + SPELL_PREVENTION_TYPE_UNK = 3 // Only a few spells have this, but most of the should be interruptable. }; enum GameobjectTypes @@ -1484,7 +1724,7 @@ enum GameobjectTypes }; #define MAX_GAMEOBJECT_TYPE 36 // sending to client this or greater value can crash client. -#define MAX_GAMEOBJECT_DATA 24 // Max number of uint32 vars in gameobject_template data field +#define MAX_GAMEOBJECT_DATA 32 // Max number of uint32 vars in gameobject_template data field enum GameObjectFlags { @@ -1770,7 +2010,8 @@ enum TextEmotes TEXT_EMOTE_LOOK = 449, TEXT_EMOTE_OBJECT = 450, TEXT_EMOTE_SWEAT = 451, - TEXT_EMOTE_YW = 453 + TEXT_EMOTE_YW = 453, + TEXT_EMOTE_READ = 456 }; // Emotes.dbc @@ -1950,7 +2191,19 @@ enum Emote EMOTE_STATE_STRANGULATE = 473, EMOTE_STATE_READY_SPELL_OMNI = 474, EMOTE_STATE_HOLD_JOUST = 475, - EMOTE_ONESHOT_CRY_JAINA = 476 + EMOTE_ONESHOT_CRY_JAINA = 476, + EMOTE_ONESHOT_SPECIAL_UNARMED = 477, + EMOTE_STATE_DANCE_NOSHEATHE = 478, + EMOTE_ONESHOT_SNIFF = 479, + EMOTE_ONESHOT_DRAGONSTOMP = 480, + EMOTE_ONESHOT_KNOCKDOWN = 482, + EMOTE_STATE_READ = 483, + EMOTE_ONESHOT_FLYEMOTETALK = 485, + EMOTE_STATE_READ_ALLOWMOVEMENT = 492, + EMOTE_STATE_READY1H_ALLOW_MOVEMENT = 505, + EMOTE_STATE_READY2H_ALLOW_MOVEMENT = 506, + EMOTE_ONESHOT_OPEN = 517, + EMOTE_STATE_READ_CHRISTMAS = 518 }; // AnimationData.dbc @@ -2461,7 +2714,161 @@ enum Anim ANIM_CARRY2H = 502, ANIM_CARRIED2H = 503, ANIM_FLY_CARRY2H = 504, - ANIM_FLY_CARRIED2H = 505 + ANIM_FLY_CARRIED2H = 505, + ANIM_EMOTE_SNIFF = 506, + ANIM_EMOTE_FLY_SNIFF = 507, + ANIM_ATTACK_FIST1H = 508, + ANIM_FLY_ATTACK_FIST1H = 509, + ANIM_ATTACK_FIST_1H_OFF = 510, + ANIM_FLY_ATTACK_FIST_1H_OFF = 511, + ANIM_PARRY_FIST1H = 512, + ANIM_FLY_PARRY_FIST1H = 513, + ANIM_READY_FIST1H = 514, + ANIM_FLY_READY_FIST1H = 515, + ANIM_SPECIAL_FIST1H = 516, + ANIM_FLY_SPECIAL_FIST1H = 517, + ANIM_EMOTE_READ_START = 518, + ANIM_FLY_EMOTE_READ_START = 519, + ANIM_EMOTE_READ_LOOP = 520, + ANIM_FLY_EMOTE_READ_LOOP = 521, + ANIM_EMOTE_READ_END = 522, + ANIM_FLY_EMOTE_READ_END = 523, + ANIM_SWIM_RUN = 524, + ANIM_FLY_SWIM_RUN = 525, + ANIM_SWIM_WALK = 526, + ANIM_FLY_SWIM_WALK = 527, + ANIM_SWIM_WALK_BACKWARDS = 528, + ANIM_FLY_SWIM_WALK_BACKWARDS = 529, + ANIM_SWIM_SPRINT = 530, + ANIM_FLY_SWIM_SPRINT = 531, + ANIM_MOUNT_SWIM_IDLE = 532, + ANIM_FLY_MOUNT_SWIM_IDLE = 533, + ANIM_MOUNT_SWIM_BACKWARDS = 534, + ANIM_FLY_MOUNT_SWIM_BACKWARDS = 535, + ANIM_MOUNT_SWIM_LEFT = 536, + ANIM_FLY_MOUNT_SWIM_LEFT = 537, + ANIM_MOUNT_SWIM_RIGHT = 538, + ANIM_FLY_MOUNT_SWIM_RIGHT = 539, + ANIM_MOUNT_SWIM_RUN = 540, + ANIM_FLY_MOUNT_SWIM_RUN = 541, + ANIM_MOUNT_SWIM_SPRINT = 542, + ANIM_FLY_MOUNT_SWIM_SPRINT = 543, + ANIM_MOUNT_SWIM_WALK = 544, + ANIM_FLY_MOUNT_SWIM_WALK = 545, + ANIM_MOUNT_SWIM_WALK_BACKWARDS = 546, + ANIM_FLY_MOUNT_SWIM_WALK_BACKWARDS = 547, + ANIM_MOUNT_FLIGHT_IDLE = 548, + ANIM_FLY_MOUNT_FLIGHT_IDLE = 549, + ANIM_MOUNT_FLIGHT_BACKWARDS = 550, + ANIM_FLY_MOUNT_FLIGHT_BACKWARDS = 551, + ANIM_MOUNT_FLIGHT_LEFT = 552, + ANIM_FLY_MOUNT_FLIGHT_LEFT = 553, + ANIM_MOUNT_FLIGHT_RIGHT = 554, + ANIM_FLY_MOUNT_FLIGHT_RIGHT = 555, + ANIM_MOUNT_FLIGHT_RUN = 556, + ANIM_FLY_MOUNT_FLIGHT_RUN = 557, + ANIM_MOUNT_FLIGHT_SPRINT = 558, + ANIM_FLY_MOUNT_FLIGHT_SPRINT = 559, + ANIM_MOUNT_FLIGHT_WALK = 560, + ANIM_FLY_MOUNT_FLIGHT_WALK = 561, + ANIM_MOUNT_FLIGHT_WALK_BACKWARDS = 562, + ANIM_FLY_MOUNT_FLIGHT_WALK_BACKWARDS = 563, + ANIM_MOUNT_FLIGHT_START = 564, + ANIM_FLY_MOUNT_FLIGHT_START = 565, + ANIM_MOUNT_SWIM_START = 566, + ANIM_FLY_MOUNT_SWIM_START = 567, + ANIM_MOUNT_SWIM_LAND = 568, + ANIM_FLY_MOUNT_SWIM_LAND = 569, + ANIM_MOUNT_SWIM_LAND_RUN = 570, + ANIM_FLY_MOUNT_SWIM_LAND_RUN = 571, + ANIM_MOUNT_FLIGHT_LAND = 572, + ANIM_FLY_MOUNT_FLIGHT_LAND = 573, + ANIM_MOUNT_FLIGHT_LAND_RUN = 574, + ANIM_FLY_MOUNT_FLIGHT_LAND_RUN = 575, + ANIM_READY_BLOW_DART = 576, + ANIM_FLY_READY_BLOW_DART = 577, + ANIM_LOAD_BLOW_DART = 578, + ANIM_FLY_LOAD_BLOW_DART = 579, + ANIM_HOLD_BLOW_DART = 580, + ANIM_FLY_HOLD_BLOW_DART = 581, + ANIM_ATTACK_BLOW_DART = 582, + ANIM_FLY_ATTACK_BLOW_DART = 583, + ANIM_CARRIAGE_MOUNT = 584, + ANIM_FLY_CARRIAGE_MOUNT = 585, + ANIM_CARRIAGE_PASSENGER_MOUNT = 586, + ANIM_FLY_CARRIAGE_PASSENGER_MOUNT = 587, + ANIM_CARRIAGE_MOUNT_ATTACK = 588, + ANIM_FLY_CARRIAGE_MOUNT_ATTACK = 589, + ANIM_BARTENDER_STAND = 590, + ANIM_FLY_BARTENDER_STAND = 591, + ANIM_BARTENDER_WALK = 592, + ANIM_FLY_BARTENDER_WALK = 593, + ANIM_BARTENDER_RUN = 594, + ANIM_FLY_BARTENDER_RUN = 595, + ANIM_BARTENDER_SHUFFLE_LEFT = 596, + ANIM_FLY_BARTENDER_SHUFFLE_LEFT = 597, + ANIM_BARTENDER_SHUFFLE_RIGHT = 598, + ANIM_FLY_BARTENDER_SHUFFLE_RIGHT = 599, + ANIM_BARTENDER_EMOTE_TALK = 600, + ANIM_FLY_BARTENDER_EMOTE_TALK = 601, + ANIM_BARTENDER_EMOTE_POINT = 602, + ANIM_FLY_BARTENDER_EMOTE_POINT = 603, + ANIM_BARMAID_STAND = 604, + ANIM_FLY_BARMAID_STAND = 605, + ANIM_BARMAID_WALK = 606, + ANIM_FLY_BARMAID_WALK = 607, + ANIM_BARMAID_RUN = 608, + ANIM_FLY_BARMAID_RUN = 609, + ANIM_BARMAID_SHUFFLE_LEFT = 610, + ANIM_FLY_BARMAID_SHUFFLE_LEFT = 611, + ANIM_BARMAID_SHUFFLE_RIGHT = 612, + ANIM_FLY_BARMAID_SHUFFLE_RIGHT = 613, + ANIM_BARMAID_EMOTE_TALK = 614, + ANIM_FLY_BARMAID_EMOTE_TALK = 615, + ANIM_BARMAID_EMOTE_POINT = 616, + ANIM_FLY_BARMAID_EMOTE_POINT = 617, + ANIM_MOUNT_SELF_IDLE = 618, + ANIM_FLY_MOUNT_SELF_IDLE = 619, + ANIM_MOUNT_SELF_WALK = 620, + ANIM_FLY_MOUNT_SELF_WALK = 621, + ANIM_MOUNT_SELF_RUN = 622, + ANIM_FLY_MOUNT_SELF_RUN = 623, + ANIM_MOUNT_SELF_SPRINT = 624, + ANIM_FLY_MOUNT_SELF_SPRINT = 625, + ANIM_MOUNT_SELF_RUN_LEFT = 626, + ANIM_FLY_MOUNT_SELF_RUN_LEFT = 627, + ANIM_MOUNT_SELF_RUN_RIGHT = 628, + ANIM_FLY_MOUNT_SELF_RUN_RIGHT = 629, + ANIM_MOUNT_SELF_SHUFFLE_LEFT = 630, + ANIM_FLY_MOUNT_SELF_SHUFFLE_LEFT = 631, + ANIM_MOUNT_SELF_SHUFFLE_RIGHT = 632, + ANIM_FLY_MOUNT_SELF_SHUFFLE_RIGHT = 633, + ANIM_MOUNT_SELF_WALK_BACKWARDS = 634, + ANIM_FLY_MOUNT_SELF_WALK_BACKWARDS = 635, + ANIM_MOUNT_SELF_SPECIAL = 636, + ANIM_FLY_MOUNT_SELF_SPECIAL = 637, + ANIM_MOUNT_SELF_JUMP = 638, + ANIM_FLY_MOUNT_SELF_JUMP = 639, + ANIM_MOUNT_SELF_JUMP_START = 640, + ANIM_FLY_MOUNT_SELF_JUMP_START = 641, + ANIM_MOUNT_SELF_JUMP_END = 642, + ANIM_FLY_MOUNT_SELF_JUMP_END = 643, + ANIM_MOUNT_SELF_JUMP_LAND_RUN = 644, + ANIM_FLY_MOUNT_SELF_JUMP_LAND_RUN = 645, + ANIM_MOUNT_SELF_START = 646, + ANIM_FLY_MOUNT_SELF_START = 647, + ANIM_MOUNT_SELF_FALL = 648, + ANIM_FLY_MOUNT_SELF_FALL = 649, + ANIM_STORMSTRIKE = 650, + ANIM_FLY_STORMSTRIKE = 651, + ANIM_READY_JOUST_NO_SHEATHE = 652, + ANIM_FLY_READY_JOUST_NO_SHEATHE = 653, + ANIM_SLAM = 654, + ANIM_FLY_SLAM = 655, + ANIM_DEATH_STRIKE = 656, + ANIM_FLY_DEATH_STRIKE = 657, + ANIM_SWIM_ATTACK_UNARMED = 658, + ANIM_FLY_SWIM_ATTACK_UNARMED = 659 }; enum LockKeyType @@ -2571,7 +2978,18 @@ enum CreatureFamily CREATURE_FAMILY_RHINO = 43, CREATURE_FAMILY_WASP = 44, CREATURE_FAMILY_CORE_HOUND = 45, - CREATURE_FAMILY_SPIRIT_BEAST = 46 + CREATURE_FAMILY_SPIRIT_BEAST = 46, + CREATURE_FAMILY_WATER_ELEMENTAL = 49, + CREATURE_FAMILY_FOX = 50, + CREATURE_FAMILY_MONKEY = 51, + CREATURE_FAMILY_DOG = 52, + CREATURE_FAMILY_BEETLE = 53, + CREATURE_FAMILY_SHALE_SPIDER = 55, + CREATURE_FAMILY_ZOMBIE = 56, + CREATURE_FAMILY_BEETLE_OLD = 57, + CREATURE_FAMILY_SILITHID_2 = 59, + CREATURE_FAMILY_WASP_2 = 66, + CREATURE_FAMILY_HYDRA = 68, }; enum CreatureTypeFlags @@ -2610,6 +3028,18 @@ enum CreatureTypeFlags CREATURE_TYPEFLAGS_UNK31 = 0x80000000 }; +enum CreatureTypeFlags2 +{ + CREATURE_TYPEFLAGS_2_UNK1 = 0x00000001, + CREATURE_TYPEFLAGS_2_UNK2 = 0x00000002, + CREATURE_TYPEFLAGS_2_UNK3 = 0x00000004, + CREATURE_TYPEFLAGS_2_UNK4 = 0x00000008, + CREATURE_TYPEFLAGS_2_UNK5 = 0x00000010, + CREATURE_TYPEFLAGS_2_UNK6 = 0x00000020, + CREATURE_TYPEFLAGS_2_UNK7 = 0x00000040, + CREATURE_TYPEFLAGS_2_UNK8 = 0x00000080 +}; + enum CreatureEliteType { CREATURE_ELITE_NORMAL = 0, @@ -2650,7 +3080,14 @@ enum HolidayIds HOLIDAY_DAY_OF_DEAD = 409, HOLIDAY_CALL_TO_ARMS_IC = 420, HOLIDAY_LOVE_IS_IN_THE_AIR = 423, - HOLIDAY_KALU_AK_FISHING_DERBY = 424 + HOLIDAY_KALU_AK_FISHING_DERBY = 424, + HOLIDAY_CALL_TO_ARMS_BFG = 435, + HOLIDAY_CALL_TO_ARMS_TP = 436, + HOLIDAY_RATED_BG_15_VS_15 = 442, + HOLIDAY_RATED_BG_25_VS_25 = 443, + HOLIDAY_ANNIVERSARY_7_YEARS = 467, + HOLIDAY_DARKMOON_FAIRE_TEROKKAR = 479, + HOLIDAY_ANNIVERSARY_8_YEARS = 484 }; // values based at QuestInfo.dbc @@ -2712,7 +3149,12 @@ enum QuestSort QUEST_SORT_JEWELCRAFTING = 373, QUEST_SORT_NOBLEGARDEN = 374, QUEST_SORT_PILGRIMS_BOUNTY = 375, - QUEST_SORT_LOVE_IS_IN_THE_AIR = 376 + QUEST_SORT_LOVE_IS_IN_THE_AIR = 376, + QUEST_SORT_ARCHAEOLOGY = 377, + QUEST_SORT_CHILDRENS_WEEK = 378, + QUEST_SORT_FIRELANDS_INVASION = 379, + QUEST_SORT_ZANDALARI = 380, + QUEST_SORT_ELEMENTAL_BONDS = 381 }; inline uint8 ClassByQuestSort(int32 QuestSort) @@ -2858,7 +3300,7 @@ enum SkillType SKILL_RACIAL_HUMAN = 754, SKILL_JEWELCRAFTING = 755, SKILL_RACIAL_BLOODELF = 756, - SKILL_PET_EVENT_RC = 758, + SKILL_PET_EVENT_RC = 758, // SkillCategory = -1 SKILL_LANG_DRAENEI = 759, SKILL_RACIAL_DRAENEI = 760, SKILL_PET_FELGUARD = 761, @@ -2886,10 +3328,34 @@ enum SkillType SKILL_PET_WASP = 785, SKILL_PET_EXOTIC_RHINO = 786, SKILL_PET_EXOTIC_CORE_HOUND = 787, - SKILL_PET_EXOTIC_SPIRIT_BEAST = 788 + SKILL_PET_EXOTIC_SPIRIT_BEAST = 788, + SKILL_RACIAL_WORGEN = 789, + SKILL_RACIAL_GOBLIN = 790, + SKILL_LANG_WORGEN = 791, + SKILL_LANG_GOBLIN = 792, + SKILL_ARCHAEOLOGY = 794, + SKILL_GENERAL_HUNTER = 795, + SKILL_GENERAL_DEATH_KNIGHT = 796, + SKILL_GENERAL_ROGUE = 797, + SKILL_GENERAL_DRUID = 798, + SKILL_GENERAL_MAGE = 799, + SKILL_GENERAL_PALADIN = 800, + SKILL_GENERAL_SHAMAN = 801, + SKILL_GENERAL_WARLOCK = 802, + SKILL_GENERAL_WARRIOR = 803, + SKILL_GENERAL_PRIEST = 804, + SKILL_PET_WATER_ELEMENTAL = 805, + SKILL_PET_FOX = 808, + SKILL_ALL_GLYPHS = 810, + SKILL_PET_DOG = 811, + SKILL_PET_MONKEY = 815, + SKILL_PET_SHALE_SPIDER = 817, + SKILL_PET_BEETLE = 818, + SKILL_ALL_GUILD_PERKS = 821, + SKILL_PET_HYDRA = 824 }; -#define MAX_SKILL_TYPE 789 +#define MAX_SKILL_TYPE 825 inline SkillType SkillByLockType(LockType locktype) { @@ -2920,12 +3386,14 @@ inline uint32 SkillByQuestSort(int32 QuestSort) case QUEST_SORT_FIRST_AID: return SKILL_FIRST_AID; case QUEST_SORT_JEWELCRAFTING: return SKILL_JEWELCRAFTING; case QUEST_SORT_INSCRIPTION: return SKILL_INSCRIPTION; + case QUEST_SORT_ARCHAEOLOGY: return SKILL_ARCHAEOLOGY; } return 0; } enum SkillCategory { + SKILL_CATEGORY_UNK1 = 0, SKILL_CATEGORY_ATTRIBUTES = 5, SKILL_CATEGORY_WEAPON = 6, SKILL_CATEGORY_CLASS = 7, @@ -2969,7 +3437,9 @@ enum TotemCategory TC_BLADED_PICKAXE = 168, TC_FLINT_AND_TINDER = 169, TC_RUNED_COBALT_ROD = 189, - TC_RUNED_TITANIUM_ROD = 190 + TC_RUNED_TITANIUM_ROD = 190, + TC_RUNED_ELEMENTIUM_ROD = 209, + TC_HIGH_POWERED_BOLT_GUN = 210, }; enum UnitDynFlags @@ -3004,62 +3474,75 @@ enum WeatherType enum ChatMsg { - CHAT_MSG_ADDON = 0xFFFFFFFF, // -1 - CHAT_MSG_SYSTEM = 0x00, - CHAT_MSG_SAY = 0x01, - CHAT_MSG_PARTY = 0x02, - CHAT_MSG_RAID = 0x03, - CHAT_MSG_GUILD = 0x04, - CHAT_MSG_OFFICER = 0x05, - CHAT_MSG_YELL = 0x06, - CHAT_MSG_WHISPER = 0x07, - CHAT_MSG_WHISPER_FOREIGN = 0x08, - CHAT_MSG_WHISPER_INFORM = 0x09, - CHAT_MSG_EMOTE = 0x0A, - CHAT_MSG_TEXT_EMOTE = 0x0B, - CHAT_MSG_MONSTER_SAY = 0x0C, - CHAT_MSG_MONSTER_PARTY = 0x0D, - CHAT_MSG_MONSTER_YELL = 0x0E, - CHAT_MSG_MONSTER_WHISPER = 0x0F, - CHAT_MSG_MONSTER_EMOTE = 0x10, - CHAT_MSG_CHANNEL = 0x11, - CHAT_MSG_CHANNEL_JOIN = 0x12, - CHAT_MSG_CHANNEL_LEAVE = 0x13, - CHAT_MSG_CHANNEL_LIST = 0x14, - CHAT_MSG_CHANNEL_NOTICE = 0x15, - CHAT_MSG_CHANNEL_NOTICE_USER = 0x16, - CHAT_MSG_AFK = 0x17, - CHAT_MSG_DND = 0x18, - CHAT_MSG_IGNORED = 0x19, - CHAT_MSG_SKILL = 0x1A, - CHAT_MSG_LOOT = 0x1B, - CHAT_MSG_MONEY = 0x1C, - CHAT_MSG_OPENING = 0x1D, - CHAT_MSG_TRADESKILLS = 0x1E, - CHAT_MSG_PET_INFO = 0x1F, - CHAT_MSG_COMBAT_MISC_INFO = 0x20, - CHAT_MSG_COMBAT_XP_GAIN = 0x21, - CHAT_MSG_COMBAT_HONOR_GAIN = 0x22, - CHAT_MSG_COMBAT_FACTION_CHANGE = 0x23, - CHAT_MSG_BG_SYSTEM_NEUTRAL = 0x24, - CHAT_MSG_BG_SYSTEM_ALLIANCE = 0x25, - CHAT_MSG_BG_SYSTEM_HORDE = 0x26, - CHAT_MSG_RAID_LEADER = 0x27, - CHAT_MSG_RAID_WARNING = 0x28, - CHAT_MSG_RAID_BOSS_EMOTE = 0x29, - CHAT_MSG_RAID_BOSS_WHISPER = 0x2A, - CHAT_MSG_FILTERED = 0x2B, - CHAT_MSG_BATTLEGROUND = 0x2C, - CHAT_MSG_BATTLEGROUND_LEADER = 0x2D, - CHAT_MSG_RESTRICTED = 0x2E, - CHAT_MSG_BATTLENET = 0x2F, - CHAT_MSG_ACHIEVEMENT = 0x30, - CHAT_MSG_GUILD_ACHIEVEMENT = 0x31, - CHAT_MSG_ARENA_POINTS = 0x32, - CHAT_MSG_PARTY_LEADER = 0x33 -}; - -#define MAX_CHAT_MSG_TYPE 0x34 + CHAT_MSG_ADDON = 0xFFFFFFFF, // -1 + CHAT_MSG_SYSTEM = 0x00, + CHAT_MSG_SAY = 0x01, + CHAT_MSG_PARTY = 0x02, + CHAT_MSG_RAID = 0x03, + CHAT_MSG_GUILD = 0x04, + CHAT_MSG_OFFICER = 0x05, + CHAT_MSG_YELL = 0x06, + CHAT_MSG_WHISPER = 0x07, + CHAT_MSG_WHISPER_FOREIGN = 0x08, + CHAT_MSG_WHISPER_INFORM = 0x09, + CHAT_MSG_EMOTE = 0x0A, + CHAT_MSG_TEXT_EMOTE = 0x0B, + CHAT_MSG_MONSTER_SAY = 0x0C, + CHAT_MSG_MONSTER_PARTY = 0x0D, + CHAT_MSG_MONSTER_YELL = 0x0E, + CHAT_MSG_MONSTER_WHISPER = 0x0F, + CHAT_MSG_MONSTER_EMOTE = 0x10, + CHAT_MSG_CHANNEL = 0x11, + CHAT_MSG_CHANNEL_JOIN = 0x12, + CHAT_MSG_CHANNEL_LEAVE = 0x13, + CHAT_MSG_CHANNEL_LIST = 0x14, + CHAT_MSG_CHANNEL_NOTICE = 0x15, + CHAT_MSG_CHANNEL_NOTICE_USER = 0x16, + CHAT_MSG_AFK = 0x17, + CHAT_MSG_DND = 0x18, + CHAT_MSG_IGNORED = 0x19, + CHAT_MSG_SKILL = 0x1A, + CHAT_MSG_LOOT = 0x1B, + CHAT_MSG_MONEY = 0x1C, + CHAT_MSG_OPENING = 0x1D, + CHAT_MSG_TRADESKILLS = 0x1E, + CHAT_MSG_PET_INFO = 0x1F, + CHAT_MSG_COMBAT_MISC_INFO = 0x20, + CHAT_MSG_COMBAT_XP_GAIN = 0x21, + CHAT_MSG_COMBAT_HONOR_GAIN = 0x22, + CHAT_MSG_COMBAT_FACTION_CHANGE = 0x23, + CHAT_MSG_BG_SYSTEM_NEUTRAL = 0x24, + CHAT_MSG_BG_SYSTEM_ALLIANCE = 0x25, + CHAT_MSG_BG_SYSTEM_HORDE = 0x26, + CHAT_MSG_RAID_LEADER = 0x27, + CHAT_MSG_RAID_WARNING = 0x28, + CHAT_MSG_RAID_BOSS_EMOTE = 0x29, + CHAT_MSG_RAID_BOSS_WHISPER = 0x2A, + CHAT_MSG_FILTERED = 0x2B, + CHAT_MSG_BATTLEGROUND = 0x2C, + CHAT_MSG_BATTLEGROUND_LEADER = 0x2D, + CHAT_MSG_RESTRICTED = 0x2E, + CHAT_MSG_BATTLENET = 0x2F, + CHAT_MSG_ACHIEVEMENT = 0x30, + CHAT_MSG_GUILD_ACHIEVEMENT = 0x31, + CHAT_MSG_ARENA_POINTS = 0x32, + CHAT_MSG_PARTY_LEADER = 0x33, + CHAT_MSG_TARGETICONS = 0x34, + CHAT_MSG_BN_WHISPER = 0x35, + CHAT_MSG_BN_WHISPER_INFORM = 0x36, + CHAT_MSG_BN_CONVERSATION = 0x37, + CHAT_MSG_BN_CONVERSATION_NOTICE = 0x38, + CHAT_MSG_BN_CONVERSATION_LIST = 0x39, + CHAT_MSG_BN_INLINE_TOAST_ALERT = 0x3A, + CHAT_MSG_BN_INLINE_TOAST_BROADCAST = 0x3B, + CHAT_MSG_BN_INLINE_TOAST_BROADCAST_INFORM = 0x3C, + CHAT_MSG_BN_INLINE_TOAST_CONVERSATION = 0x3D, + CHAT_MSG_BN_WHISPER_PLAYER_OFFLINE = 0x3E, + CHAT_MSG_COMBAT_GUILD_XP_GAIN = 0x3F, + CHAT_MSG_CURRENCY = 0x40 +}; + +#define MAX_CHAT_MSG_TYPE 0x41 enum ChatLinkColors { @@ -3092,6 +3575,7 @@ enum GuildLogs { GUILD_BANKLOG_MAX_RECORDS = 25, GUILD_EVENTLOG_MAX_RECORDS = 100, + GUILD_NEWSLOG_MAX_RECORDS = 250 }; enum AiReaction @@ -3162,7 +3646,8 @@ enum SummonType SUMMON_TYPE_VEHICLE = 9, SUMMON_TYPE_VEHICLE2 = 10, // Oculus and Argent Tournament vehicles (3.3.5a) SUMMON_TYPE_LIGHTWELL = 11, - SUMMON_TYPE_JEEVES = 12 + SUMMON_TYPE_JEEVES = 12, + SUMMON_TYPE_UNK13 = 13 }; enum EventId @@ -3261,36 +3746,38 @@ enum ResponseCodes CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 73, CHAR_DELETE_FAILED_GUILD_LEADER = 74, CHAR_DELETE_FAILED_ARENA_CAPTAIN = 75, - - CHAR_LOGIN_IN_PROGRESS = 76, - CHAR_LOGIN_SUCCESS = 77, - CHAR_LOGIN_NO_WORLD = 78, - CHAR_LOGIN_DUPLICATE_CHARACTER = 79, - CHAR_LOGIN_NO_INSTANCES = 80, - CHAR_LOGIN_FAILED = 81, - CHAR_LOGIN_DISABLED = 82, - CHAR_LOGIN_NO_CHARACTER = 83, - CHAR_LOGIN_LOCKED_FOR_TRANSFER = 84, - CHAR_LOGIN_LOCKED_BY_BILLING = 85, - CHAR_LOGIN_LOCKED_BY_MOBILE_AH = 86, - - CHAR_NAME_SUCCESS = 87, - CHAR_NAME_FAILURE = 88, - CHAR_NAME_NO_NAME = 89, - CHAR_NAME_TOO_SHORT = 90, - CHAR_NAME_TOO_LONG = 91, - CHAR_NAME_INVALID_CHARACTER = 92, - CHAR_NAME_MIXED_LANGUAGES = 93, - CHAR_NAME_PROFANE = 94, - CHAR_NAME_RESERVED = 95, - CHAR_NAME_INVALID_APOSTROPHE = 96, - CHAR_NAME_MULTIPLE_APOSTROPHES = 97, - CHAR_NAME_THREE_CONSECUTIVE = 98, - CHAR_NAME_INVALID_SPACE = 99, - CHAR_NAME_CONSECUTIVE_SPACES = 100, - CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 101, - CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 102, - CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 103 + CHAR_DELETE_FAILED_HAS_HEIRLOOM_OR_MAIL = 76, + + CHAR_LOGIN_IN_PROGRESS = 77, + CHAR_LOGIN_SUCCESS = 78, + CHAR_LOGIN_NO_WORLD = 79, + CHAR_LOGIN_DUPLICATE_CHARACTER = 80, + CHAR_LOGIN_NO_INSTANCES = 81, + CHAR_LOGIN_FAILED = 82, + CHAR_LOGIN_DISABLED = 83, + CHAR_LOGIN_NO_CHARACTER = 84, + CHAR_LOGIN_LOCKED_FOR_TRANSFER = 85, + CHAR_LOGIN_LOCKED_BY_BILLING = 86, + CHAR_LOGIN_LOCKED_BY_MOBILE_AH = 87, + CHAR_LOGIN_TEMPORARY_GM_LOCK = 88, + + CHAR_NAME_SUCCESS = 89, + CHAR_NAME_FAILURE = 90, + CHAR_NAME_NO_NAME = 91, + CHAR_NAME_TOO_SHORT = 92, + CHAR_NAME_TOO_LONG = 93, + CHAR_NAME_INVALID_CHARACTER = 94, + CHAR_NAME_MIXED_LANGUAGES = 95, + CHAR_NAME_PROFANE = 96, + CHAR_NAME_RESERVED = 97, + CHAR_NAME_INVALID_APOSTROPHE = 98, + CHAR_NAME_MULTIPLE_APOSTROPHES = 99, + CHAR_NAME_THREE_CONSECUTIVE = 100, + CHAR_NAME_INVALID_SPACE = 101, + CHAR_NAME_CONSECUTIVE_SPACES = 102, + CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 103, + CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 104, + CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 105, }; /// Ban function modes @@ -3321,23 +3808,31 @@ enum BattlegroundTeamId // indexes of BattlemasterList.dbc enum BattlegroundTypeId { - BATTLEGROUND_TYPE_NONE = 0, // None - BATTLEGROUND_AV = 1, // Alterac Valley - BATTLEGROUND_WS = 2, // Warsong Gulch - BATTLEGROUND_AB = 3, // Arathi Basin - BATTLEGROUND_NA = 4, // Nagrand Arena - BATTLEGROUND_BE = 5, // Blade's Edge Arena - BATTLEGROUND_AA = 6, // All Arenas - BATTLEGROUND_EY = 7, // Eye of the Storm - BATTLEGROUND_RL = 8, // Ruins of Lordaernon - BATTLEGROUND_SA = 9, // Strand of the Ancients - BATTLEGROUND_DS = 10, // Dalaran Sewers - BATTLEGROUND_RV = 11, // Ring of Valor - BATTLEGROUND_IC = 30, // Isle of Conquest - BATTLEGROUND_RB = 32 // Random Battleground + BATTLEGROUND_TYPE_NONE = 0, // None + BATTLEGROUND_AV = 1, // Alterac Valley + BATTLEGROUND_WS = 2, // Warsong Gulch + BATTLEGROUND_AB = 3, // Arathi Basin + BATTLEGROUND_NA = 4, // Nagrand Arena + BATTLEGROUND_BE = 5, // Blade's Edge Arena + BATTLEGROUND_AA = 6, // All Arenas + BATTLEGROUND_EY = 7, // Eye of the Storm + BATTLEGROUND_RL = 8, // Ruins of Lordaernon + BATTLEGROUND_SA = 9, // Strand of the Ancients + BATTLEGROUND_DS = 10, // Dalaran Sewers + BATTLEGROUND_RV = 11, // Ring of Valor + BATTLEGROUND_IC = 30, // Isle of Conquest + BATTLEGROUND_RB = 32, // Random Battleground + BATTLEGROUND_RATED_10_VS_10 = 100, // Rated BG 10 vs 10 + BATTLEGROUND_RATED_15_VS_15 = 101, // Rated BG 15 vs 15 + BATTLEGROUND_RATED_25_VS_25 = 102, // Rated BG 25 vs 25 + BATTLEGROUND_TP = 108, // Twin Peaks + BATTLEGROUND_BFG = 120, // Battle For Gilneas + // 441 = "Icecrown Citadel" + // 443 = "The Ruby Sanctum" + // 656 = "Rated Eye of the Storm" }; -#define MAX_BATTLEGROUND_TYPE_ID 33 +#define MAX_BATTLEGROUND_TYPE_ID 121 enum MailResponseType { @@ -3386,35 +3881,44 @@ enum SpellFamilyNames // 14 - unused SPELLFAMILY_DEATHKNIGHT = 15, // 16 - unused - SPELLFAMILY_PET = 17 + SPELLFAMILY_PET = 17, + SPELLFAMILY_UNK3 = 50, }; enum TradeStatus { - TRADE_STATUS_BUSY = 0, - TRADE_STATUS_BEGIN_TRADE = 1, - TRADE_STATUS_OPEN_WINDOW = 2, - TRADE_STATUS_TRADE_CANCELED = 3, - TRADE_STATUS_TRADE_ACCEPT = 4, - TRADE_STATUS_BUSY_2 = 5, - TRADE_STATUS_NO_TARGET = 6, - TRADE_STATUS_BACK_TO_TRADE = 7, - TRADE_STATUS_TRADE_COMPLETE = 8, - // 9? - TRADE_STATUS_TARGET_TO_FAR = 10, - TRADE_STATUS_WRONG_FACTION = 11, - TRADE_STATUS_CLOSE_WINDOW = 12, - // 13? - TRADE_STATUS_IGNORE_YOU = 14, - TRADE_STATUS_YOU_STUNNED = 15, - TRADE_STATUS_TARGET_STUNNED = 16, - TRADE_STATUS_YOU_DEAD = 17, - TRADE_STATUS_TARGET_DEAD = 18, - TRADE_STATUS_YOU_LOGOUT = 19, - TRADE_STATUS_TARGET_LOGOUT = 20, - TRADE_STATUS_TRIAL_ACCOUNT = 21, // Trial accounts can not perform that action - TRADE_STATUS_ONLY_CONJURED = 22, // You can only trade conjured items... (cross realm BG related). - TRADE_STATUS_NOT_ELIGIBLE = 23 // Related to trading soulbound loot items + TRADE_STATUS_OPEN_WINDOW = 0, + // 1 - Related to EVENT_PLAYER_MONEY + TRADE_STATUS_NOT_ELIGIBLE = 2, // Related to trading soulbound loot items + TRADE_STATUS_YOU_LOGOUT = 3, + TRADE_STATUS_IGNORE_YOU = 4, + TRADE_STATUS_TARGET_DEAD = 5, + TRADE_STATUS_TRADE_ACCEPT = 6, + TRADE_STATUS_TARGET_LOGOUT = 7, + // 8 - nonexistent + TRADE_STATUS_TRADE_COMPLETE = 9, + TRADE_STATUS_TRIAL_ACCOUNT = 10, // Trial accounts can not perform that action + // 11 - nonexistent + TRADE_STATUS_BEGIN_TRADE = 12, + TRADE_STATUS_YOU_DEAD = 13, + // 14 - nonexistent + // 15 - nonexistent + TRADE_STATUS_TARGET_TO_FAR = 16, + TRADE_STATUS_NO_TARGET = 17, + TRADE_STATUS_BUSY_2 = 18, + TRADE_STATUS_CURRENCY_NOT_TRADABLE = 19, // new 4.x + TRADE_STATUS_WRONG_FACTION = 20, + TRADE_STATUS_BUSY = 21, + // 22 - equivalent to 335 unk status 9 + TRADE_STATUS_TRADE_CANCELED = 23, + TRADE_STATUS_CURRENCY = 24, // new 4.x + TRADE_STATUS_BACK_TO_TRADE = 25, + TRADE_STATUS_ONLY_CONJURED = 26, // You can only trade conjured items... (cross realm BG related). + TRADE_STATUS_YOU_STUNNED = 27, + // 28 - nonexistent + TRADE_STATUS_TARGET_STUNNED = 29, + // 30 - nonexistent + TRADE_STATUS_CLOSE_WINDOW = 31, }; enum XPColorChar @@ -3451,6 +3955,12 @@ enum ActivateTaxiReply ERR_TAXINOTSTANDING = 12 }; +enum ProfessionUI +{ + MAX_PRIMARY_PROFESSIONS = 2, + MAX_SECONDARY_SKILLS = 5 +}; + enum DuelCompleteType { DUEL_INTERRUPTED = 0, @@ -3468,32 +3978,44 @@ enum BattlegroundQueueTypeId BATTLEGROUND_QUEUE_EY = 4, BATTLEGROUND_QUEUE_SA = 5, BATTLEGROUND_QUEUE_IC = 6, - BATTLEGROUND_QUEUE_RB = 7, - BATTLEGROUND_QUEUE_2v2 = 8, - BATTLEGROUND_QUEUE_3v3 = 9, - BATTLEGROUND_QUEUE_5v5 = 10, + BATTLEGROUND_QUEUE_TP = 7, + BATTLEGROUND_QUEUE_BFG = 8, + BATTLEGROUND_QUEUE_RB = 9, + BATTLEGROUND_QUEUE_2v2 = 10, + BATTLEGROUND_QUEUE_3v3 = 11, + BATTLEGROUND_QUEUE_5v5 = 12, MAX_BATTLEGROUND_QUEUE_TYPES }; enum GroupJoinBattlegroundResult { - // positive values are indexes in BattlemasterList.dbc - ERR_GROUP_JOIN_BATTLEGROUND_FAIL = 0, // Your group has joined a battleground queue, but you are not eligible (showed for non existing BattlemasterList.dbc indexes) - ERR_BATTLEGROUND_NONE = -1, // not show anything - ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS = -2, // You cannot join the battleground yet because you or one of your party members is flagged as a Deserter. - ERR_ARENA_TEAM_PARTY_SIZE = -3, // Incorrect party size for this arena. - ERR_BATTLEGROUND_TOO_MANY_QUEUES = -4, // You can only be queued for 2 battles at once - ERR_BATTLEGROUND_CANNOT_QUEUE_FOR_RATED = -5, // You cannot queue for a rated match while queued for other battles - ERR_BATTLEDGROUND_QUEUED_FOR_RATED = -6, // You cannot queue for another battle while queued for a rated arena match - ERR_BATTLEGROUND_TEAM_LEFT_QUEUE = -7, // Your team has left the arena queue - ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND = -8, // You can't do that in a battleground. - ERR_BATTLEGROUND_JOIN_XP_GAIN = -9, // wtf, doesn't exist in client... - ERR_BATTLEGROUND_JOIN_RANGE_INDEX = -10, // Cannot join the queue unless all members of your party are in the same battleground level range. - ERR_BATTLEGROUND_JOIN_TIMED_OUT = -11, // %s was unavailable to join the queue. (uint64 guid exist in client cache) - ERR_BATTLEGROUND_JOIN_FAILED = -12, // Join as a group failed (uint64 guid doesn't exist in client cache) - ERR_LFG_CANT_USE_BATTLEGROUND = -13, // You cannot queue for a battleground or arena while using the dungeon system. - ERR_IN_RANDOM_BG = -14, // Can't do that while in a Random Battleground queue. - ERR_IN_NON_RANDOM_BG = -15 // Can't queue for Random Battleground while in another Battleground queue. + ERR_BATTLEGROUND_NONE = 0, + ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS = 2, // You cannot join the battleground yet because you or one of your party members is flagged as a Deserter. + ERR_ARENA_TEAM_PARTY_SIZE = 3, // Incorrect party size for this arena. + ERR_BATTLEGROUND_TOO_MANY_QUEUES = 4, // You can only be queued for 2 battles at once + ERR_BATTLEGROUND_CANNOT_QUEUE_FOR_RATED = 5, // You cannot queue for a rated match while queued for other battles + ERR_BATTLEDGROUND_QUEUED_FOR_RATED = 6, // You cannot queue for another battle while queued for a rated arena match + ERR_BATTLEGROUND_TEAM_LEFT_QUEUE = 7, // Your team has left the arena queue + ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND = 8, // You can't do that in a battleground. + ERR_BATTLEGROUND_JOIN_XP_GAIN = 9, // wtf, doesn't exist in client... + ERR_BATTLEGROUND_JOIN_RANGE_INDEX = 10, // Cannot join the queue unless all members of your party are in the same battleground level range. + ERR_BATTLEGROUND_JOIN_TIMED_OUT = 11, // %s was unavailable to join the queue. (uint64 guid exist in client cache) + //ERR_BATTLEGROUND_JOIN_TIMED_OUT = 12, // same as 11 + //ERR_BATTLEGROUND_TEAM_LEFT_QUEUE = 13, // same as 7 + ERR_LFG_CANT_USE_BATTLEGROUND = 14, // You cannot queue for a battleground or arena while using the dungeon system. + ERR_IN_RANDOM_BG = 15, // Can't do that while in a Random Battleground queue. + ERR_IN_NON_RANDOM_BG = 16, // Can't queue for Random Battleground while in another Battleground queue. + ERR_BG_DEVELOPER_ONLY = 17, + ERR_BATTLEGROUND_INVITATION_DECLINED = 18, + ERR_MEETING_STONE_NOT_FOUND = 19, + ERR_WARGAME_REQUEST_FAILURE = 20, + ERR_BATTLEFIELD_TEAM_PARTY_SIZE = 22, + ERR_NOT_ON_TOURNAMENT_REALM = 23, + ERR_BATTLEGROUND_PLAYERS_FROM_DIFFERENT_REALMS = 24, + ERR_REMOVE_FROM_PVP_QUEUE_GRANT_LEVEL = 33, + ERR_REMOVE_FROM_PVP_QUEUE_FACTION_CHANGE = 34, + ERR_BATTLEGROUND_JOIN_FAILED = 35, + ERR_BATTLEGROUND_DUPE_QUEUE = 43 }; enum PetNameInvalidReason @@ -3527,6 +4049,28 @@ enum DungeonStatusFlag RAID_STATUSFLAG_25MAN_HEROIC = 0x08 }; +#define VOID_STORAGE_UNLOCK 100*GOLD +#define VOID_STORAGE_STORE_ITEM 25*GOLD +#define VOID_STORAGE_MAX_DEPOSIT 9 +#define VOID_STORAGE_MAX_WITHDRAW 9 +#define VOID_STORAGE_MAX_SLOT 80 + +enum VoidTransferError +{ + VOID_TRANSFER_ERROR_NO_ERROR = 0, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_1 = 1, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_2 = 2, + VOID_TRANSFER_ERROR_FULL = 3, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_3 = 4, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_4 = 5, + VOID_TRANSFER_ERROR_NOT_ENOUGH_MONEY = 6, + VOID_TRANSFER_ERROR_INVENTORY_FULL = 7, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_5 = 8, + VOID_TRANSFER_ERROR_TRANSFER_UNKNOWN = 9, +}; + +#define CURRENCY_PRECISION 100 + enum PartyResult { ERR_PARTY_RESULT_OK = 0, diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 55f745d993b..72bb0e1d56e 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -403,10 +403,7 @@ void MotionMaster::MoveFall(uint32 id /*=0*/) return; if (_owner->GetTypeId() == TYPEID_PLAYER) - { - _owner->AddUnitMovementFlag(MOVEMENTFLAG_FALLING); - _owner->m_movementInfo.SetFallTime(0); - } + _owner->SetFall(true); Movement::MoveSplineInit init(_owner); init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz, false); diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp index 0a8a9f267dd..2b2b9bec288 100755..100644 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp @@ -19,6 +19,7 @@ #include "IdleMovementGenerator.h" #include "CreatureAI.h" #include "Creature.h" +#include <G3D/g3dmath.h> IdleMovementGenerator si_idleMovement; @@ -44,25 +45,17 @@ void RotateMovementGenerator::Initialize(Unit* owner) owner->SetInFront(owner->GetVictim()); owner->AddUnitState(UNIT_STATE_ROTATING); - owner->AttackStop(); } bool RotateMovementGenerator::Update(Unit* owner, uint32 diff) { float angle = owner->GetOrientation(); - if (m_direction == ROTATE_DIRECTION_LEFT) - { - angle += (float)diff * static_cast<float>(M_PI * 2) / m_maxDuration; - while (angle >= static_cast<float>(M_PI * 2)) angle -= static_cast<float>(M_PI * 2); - } - else - { - angle -= (float)diff * static_cast<float>(M_PI * 2) / m_maxDuration; - while (angle < 0) angle += static_cast<float>(M_PI * 2); - } + angle += (float(diff) * static_cast<float>(M_PI * 2) / m_maxDuration) * (m_direction == ROTATE_DIRECTION_LEFT ? 1.0f : -1.0f); + angle = G3D::wrap(angle, 0.0f, float(G3D::twoPi())); - owner->SetFacingTo(angle); + owner->SetOrientation(angle); // UpdateSplinePosition does not set orientation with UNIT_STATE_ROTATING + owner->SetFacingTo(angle); // Send spline movement to clients if (m_duration > diff) m_duration -= diff; diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index c59762066ae..c59762066ae 100644..100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 4061998d47a..8cde9876ca1 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -102,7 +102,7 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature) if (Stopped()) return true; - bool transportPath = creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && creature->GetTransGUID(); + bool transportPath = creature->GetTransport() != NULL; if (m_isArrivalDone) { @@ -210,7 +210,7 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di else { // Set home position at place on waypoint movement. - if (!creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) || !creature->GetTransGUID()) + if (!creature->GetTransGUID()) creature->SetHomePosition(creature->GetPosition()); if (creature->IsStopped()) @@ -302,6 +302,9 @@ void FlightPathMovementGenerator::DoReset(Player* player) } init.SetFirstPointId(GetCurrentNode()); init.SetFly(); + init.SetSmooth(); + init.SetUncompressed(); + init.SetWalk(true); init.SetVelocity(PLAYER_FLIGHT_SPEED); init.Launch(); } diff --git a/src/server/game/Movement/MovementStructures.cpp b/src/server/game/Movement/MovementStructures.cpp new file mode 100644 index 00000000000..242b2aeaca7 --- /dev/null +++ b/src/server/game/Movement/MovementStructures.cpp @@ -0,0 +1,5451 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "MovementStructures.h" +#include "Player.h" + +MovementStatusElements const PlayerMove[] = +{ + MSEHasFallData, + MSEHasGuidByte3, + MSEHasGuidByte6, + MSEHasMovementFlags2, + MSEHasSpline, + MSEHasTimestamp, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEMovementFlags2, + MSEHasGuidByte7, + MSEHasMovementFlags, + MSEHasOrientation, + MSEHasGuidByte2, + MSEHasSplineElevation, + MSEZeroBit, + MSEHasGuidByte4, + MSEHasFallDirection, + MSEHasGuidByte5, + MSEHasTransportData, + MSEMovementFlags, + MSEHasTransportGuidByte3, + MSEHasTransportTime3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte4, + MSEHasTransportTime2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte2, + MSEHasPitch, + MSEGuidByte5, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSESplineElevation, + MSEGuidByte7, + MSEPositionY, + MSEGuidByte3, + MSETransportTime3, + MSETransportGuidByte6, + MSETransportSeat, + MSETransportGuidByte5, + MSETransportPositionX, + MSETransportGuidByte1, + MSETransportOrientation, + MSETransportGuidByte2, + MSETransportTime2, + MSETransportGuidByte0, + MSETransportPositionZ, + MSETransportGuidByte7, + MSETransportGuidByte4, + MSETransportGuidByte3, + MSETransportPositionY, + MSETransportTime, + MSEGuidByte4, + MSEPositionX, + MSEGuidByte6, + MSEPositionZ, + MSETimestamp, + MSEGuidByte2, + MSEPitch, + MSEGuidByte0, + MSEOrientation, + MSEGuidByte1, + MSEEnd, +}; + +MovementStatusElements const MovementFallLand[] = +{ + MSEPositionX, + MSEPositionY, + MSEPositionZ, + MSEHasTransportData, + MSEHasGuidByte7, + MSEHasGuidByte1, + MSEHasMovementFlags2, + MSEHasGuidByte3, + MSEHasSplineElevation, + MSEHasOrientation, + MSEHasGuidByte6, + MSEHasTimestamp, + MSEZeroBit, + MSEHasPitch, + MSEHasGuidByte4, + MSEHasSpline, + MSEHasGuidByte5, + MSEHasMovementFlags, + MSEHasFallData, + MSEHasGuidByte0, + MSEHasGuidByte2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportTime2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte7, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte5, + MSETransportTime, + MSETransportPositionZ, + MSETransportPositionY, + MSETransportPositionX, + MSETransportGuidByte5, + MSETransportTime3, + MSETransportGuidByte1, + MSETransportSeat, + MSETransportTime2, + MSETransportGuidByte4, + MSETransportOrientation, + MSETransportGuidByte0, + MSETransportGuidByte7, + MSETransportGuidByte3, + MSETransportGuidByte6, + MSETransportGuidByte2, + MSEFallVerticalSpeed, + MSEFallTime, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSESplineElevation, + MSETimestamp, + MSEPitch, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementHeartBeat[] = +{ + MSEPositionZ, + MSEPositionX, + MSEPositionY, + MSEHasPitch, + MSEHasTimestamp, + MSEHasFallData, + MSEHasMovementFlags2, + MSEHasTransportData, + MSEHasGuidByte7, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasOrientation, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEHasSplineElevation, + MSEHasSpline, + MSEZeroBit, + MSEHasGuidByte6, + MSEHasMovementFlags, + MSEHasTransportTime3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte2, + MSEHasTransportTime2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasFallDirection, + MSEMovementFlags, + MSEMovementFlags2, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte5, + MSEGuidByte0, + MSEGuidByte4, + MSETransportPositionZ, + MSETransportSeat, + MSETransportOrientation, + MSETransportGuidByte4, + MSETransportPositionY, + MSETransportTime, + MSETransportPositionX, + MSETransportGuidByte5, + MSETransportGuidByte1, + MSETransportGuidByte3, + MSETransportGuidByte7, + MSETransportTime3, + MSETransportTime2, + MSETransportGuidByte2, + MSETransportGuidByte0, + MSETransportGuidByte6, + MSEOrientation, + MSEFallVerticalSpeed, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEPitch, + MSESplineElevation, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const MovementJump[] = +{ + MSEPositionY, + MSEPositionX, + MSEPositionZ, + MSEHasTimestamp, + MSEHasGuidByte5, + MSEHasMovementFlags, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasMovementFlags2, + MSEHasGuidByte0, + MSEHasTransportData, + MSEHasGuidByte3, + MSEHasPitch, + MSEHasGuidByte7, + MSEHasFallData, + MSEHasSpline, + MSEHasOrientation, + MSEHasGuidByte1, + MSEHasSplineElevation, + MSEZeroBit, + MSEHasGuidByte2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte4, + MSEHasTransportTime3, + MSEHasTransportTime2, + MSEHasTransportGuidByte2, + MSEHasFallDirection, + MSEMovementFlags, + MSEMovementFlags2, + MSEGuidByte6, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte7, + MSEGuidByte1, + MSETransportGuidByte1, + MSETransportGuidByte7, + MSETransportPositionX, + MSETransportGuidByte4, + MSETransportTime3, + MSETransportGuidByte0, + MSETransportOrientation, + MSETransportTime2, + MSETransportTime, + MSETransportGuidByte6, + MSETransportPositionZ, + MSETransportSeat, + MSETransportPositionY, + MSETransportGuidByte3, + MSETransportGuidByte2, + MSETransportGuidByte5, + MSEPitch, + MSETimestamp, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallVerticalSpeed, + MSEFallTime, + MSESplineElevation, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementSetFacing[] = +{ + MSEPositionX, + MSEPositionY, + MSEPositionZ, + MSEHasGuidByte6, + MSEHasTransportData, + MSEHasGuidByte4, + MSEHasSpline, + MSEHasGuidByte0, + MSEHasOrientation, + MSEHasTimestamp, + MSEHasPitch, + MSEHasMovementFlags2, + MSEHasGuidByte5, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasFallData, + MSEHasSplineElevation, + MSEHasMovementFlags, + MSEHasGuidByte3, + MSEZeroBit, + MSEHasGuidByte1, + MSEHasTransportTime3, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEHasTransportTime2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte1, + MSEHasFallDirection, + MSEMovementFlags2, + MSEMovementFlags, + MSEGuidByte6, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte3, + MSETransportGuidByte0, + MSETransportPositionX, + MSETransportGuidByte1, + MSETransportTime2, + MSETransportGuidByte4, + MSETransportPositionZ, + MSETransportOrientation, + MSETransportGuidByte2, + MSETransportTime3, + MSETransportGuidByte3, + MSETransportSeat, + MSETransportPositionY, + MSETransportGuidByte5, + MSETransportGuidByte6, + MSETransportTime, + MSETransportGuidByte7, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallTime, + MSEFallVerticalSpeed, + MSESplineElevation, + MSEOrientation, + MSETimestamp, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementSetPitch[] = +{ + MSEPositionX, + MSEPositionZ, + MSEPositionY, + MSEHasFallData, + MSEHasMovementFlags, + MSEHasGuidByte1, + MSEHasOrientation, + MSEHasGuidByte7, + MSEHasGuidByte3, + MSEHasMovementFlags2, + MSEHasTransportData, + MSEHasSplineElevation, + MSEHasGuidByte6, + MSEHasPitch, + MSEHasGuidByte4, + MSEHasSpline, + MSEHasGuidByte2, + MSEZeroBit, + MSEHasTimestamp, + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte5, + MSEHasTransportTime3, + MSEHasTransportGuidByte7, + MSEHasTransportTime2, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte3, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte2, + MSEGuidByte4, + MSETransportGuidByte4, + MSETransportGuidByte3, + MSETransportGuidByte6, + MSETransportOrientation, + MSETransportGuidByte1, + MSETransportTime3, + MSETransportTime, + MSETransportGuidByte2, + MSETransportPositionZ, + MSETransportGuidByte0, + MSETransportTime2, + MSETransportPositionY, + MSETransportGuidByte5, + MSETransportSeat, + MSETransportGuidByte7, + MSETransportPositionX, + MSEFallVerticalSpeed, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEPitch, + MSESplineElevation, + MSETimestamp, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementStartBackward[] = +{ + MSEPositionX, + MSEPositionZ, + MSEPositionY, + MSEHasTransportData, + MSEHasGuidByte3, + MSEHasGuidByte0, + MSEHasGuidByte2, + MSEHasTimestamp, + MSEHasGuidByte7, + MSEHasPitch, + MSEZeroBit, + MSEHasMovementFlags, + MSEHasOrientation, + MSEHasSpline, + MSEHasMovementFlags2, + MSEHasFallData, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasSplineElevation, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasTransportTime2, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte4, + MSEHasTransportTime3, + MSEMovementFlags, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte6, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte3, + MSETransportPositionZ, + MSETransportGuidByte2, + MSETransportTime3, + MSETransportGuidByte0, + MSETransportGuidByte5, + MSETransportPositionY, + MSETransportGuidByte1, + MSETransportPositionX, + MSETransportTime2, + MSETransportGuidByte4, + MSETransportOrientation, + MSETransportSeat, + MSETransportGuidByte7, + MSETransportTime, + MSETransportGuidByte6, + MSETransportGuidByte3, + MSEPitch, + MSETimestamp, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSEOrientation, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementStartForward[] = +{ + MSEPositionY, + MSEPositionZ, + MSEPositionX, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEZeroBit, + MSEHasMovementFlags, + MSEHasGuidByte7, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasOrientation, + MSEHasGuidByte6, + MSEHasSpline, + MSEHasSplineElevation, + MSEHasGuidByte4, + MSEHasTransportData, + MSEHasTimestamp, + MSEHasPitch, + MSEHasMovementFlags2, + MSEHasFallData, + MSEMovementFlags, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte1, + MSEHasTransportTime3, + MSEHasTransportTime2, + MSEHasFallDirection, + MSEMovementFlags2, + MSEGuidByte2, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte5, + MSEGuidByte0, + MSEFallVerticalSpeed, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallTime, + MSETransportGuidByte3, + MSETransportPositionY, + MSETransportPositionZ, + MSETransportGuidByte1, + MSETransportGuidByte4, + MSETransportGuidByte7, + MSETransportOrientation, + MSETransportGuidByte2, + MSETransportPositionX, + MSETransportGuidByte5, + MSETransportTime3, + MSETransportTime, + MSETransportGuidByte6, + MSETransportGuidByte0, + MSETransportSeat, + MSETransportTime2, + MSESplineElevation, + MSEPitch, + MSEOrientation, + MSETimestamp, + + MSEEnd, +}; + +MovementStatusElements const MovementStartStrafeLeft[] = +{ + MSEPositionZ, + MSEPositionX, + MSEPositionY, + MSEHasSplineElevation, + MSEHasGuidByte5, + MSEHasPitch, + MSEHasGuidByte6, + MSEHasTimestamp, + MSEHasGuidByte1, + MSEZeroBit, + MSEHasGuidByte4, + MSEHasGuidByte0, + MSEHasGuidByte2, + MSEHasFallData, + MSEHasOrientation, + MSEHasGuidByte3, + MSEHasMovementFlags2, + MSEHasGuidByte7, + MSEHasSpline, + MSEHasMovementFlags, + MSEHasTransportData, + MSEHasFallDirection, + MSEHasTransportTime2, + MSEHasTransportGuidByte7, + MSEHasTransportTime3, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte0, + MSEMovementFlags, + MSEMovementFlags2, + MSEGuidByte2, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte5, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallTime, + MSEFallVerticalSpeed, + MSETransportSeat, + MSETransportGuidByte2, + MSETransportTime2, + MSETransportGuidByte3, + MSETransportPositionZ, + MSETransportTime3, + MSETransportGuidByte0, + MSETransportGuidByte7, + MSETransportPositionY, + MSETransportGuidByte5, + MSETransportGuidByte1, + MSETransportOrientation, + MSETransportTime, + MSETransportGuidByte6, + MSETransportGuidByte4, + MSETransportPositionX, + MSETimestamp, + MSEOrientation, + MSEPitch, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementStartStrafeRight[] = +{ + MSEPositionY, + MSEPositionX, + MSEPositionZ, + MSEHasPitch, + MSEHasGuidByte1, + MSEHasOrientation, + MSEHasGuidByte4, + MSEHasSpline, + MSEZeroBit, + MSEHasGuidByte5, + MSEHasFallData, + MSEHasSplineElevation, + MSEHasTimestamp, + MSEHasMovementFlags, + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEHasMovementFlags2, + MSEHasTransportData, + MSEHasGuidByte0, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte0, + MSEHasTransportTime2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte4, + MSEHasTransportTime3, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte7, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte0, + MSETransportGuidByte5, + MSETransportGuidByte1, + MSETransportGuidByte6, + MSETransportPositionY, + MSETransportOrientation, + MSETransportGuidByte0, + MSETransportGuidByte2, + MSETransportSeat, + MSETransportPositionX, + MSETransportTime3, + MSETransportTime, + MSETransportGuidByte4, + MSETransportGuidByte7, + MSETransportTime2, + MSETransportPositionZ, + MSETransportGuidByte3, + MSEPitch, + MSEOrientation, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + MSEFallVerticalSpeed, + MSETimestamp, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementStartTurnLeft[] = +{ + MSEPositionY, + MSEPositionX, + MSEPositionZ, + MSEZeroBit, + MSEHasGuidByte1, + MSEHasOrientation, + MSEHasSpline, + MSEHasMovementFlags, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasMovementFlags2, + MSEHasGuidByte5, + MSEHasGuidByte7, + MSEHasTransportData, + MSEHasGuidByte6, + MSEHasSplineElevation, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasPitch, + MSEHasTimestamp, + MSEHasFallData, + MSEMovementFlags2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte0, + MSEHasTransportTime2, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte6, + MSEHasFallDirection, + MSEMovementFlags, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte1, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallVerticalSpeed, + MSEFallTime, + MSETransportGuidByte0, + MSETransportPositionX, + MSETransportTime, + MSETransportSeat, + MSETransportPositionZ, + MSETransportGuidByte4, + MSETransportOrientation, + MSETransportGuidByte2, + MSETransportGuidByte6, + MSETransportGuidByte1, + MSETransportGuidByte3, + MSETransportPositionY, + MSETransportTime3, + MSETransportTime2, + MSETransportGuidByte5, + MSETransportGuidByte7, + MSETimestamp, + MSEPitch, + MSEOrientation, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementStartTurnRight[] = +{ + MSEPositionX, + MSEPositionZ, + MSEPositionY, + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasMovementFlags, + MSEHasSpline, + MSEHasGuidByte0, + MSEHasOrientation, + MSEHasTransportData, + MSEHasGuidByte7, + MSEZeroBit, + MSEHasMovementFlags2, + MSEHasGuidByte1, + MSEHasTimestamp, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasSplineElevation, + MSEHasPitch, + MSEHasFallData, + MSEHasTransportGuidByte1, + MSEHasTransportTime2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte7, + MSEHasTransportTime3, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte5, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte4, + MSEGuidByte6, + MSETransportPositionY, + MSETransportGuidByte0, + MSETransportGuidByte4, + MSETransportGuidByte1, + MSETransportGuidByte6, + MSETransportGuidByte2, + MSETransportSeat, + MSETransportOrientation, + MSETransportGuidByte5, + MSETransportTime3, + MSETransportPositionZ, + MSETransportPositionX, + MSETransportTime, + MSETransportGuidByte7, + MSETransportGuidByte3, + MSETransportTime2, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallTime, + MSEFallVerticalSpeed, + MSEPitch, + MSEOrientation, + MSESplineElevation, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const MovementStop[] = +{ + MSEPositionX, + MSEPositionY, + MSEPositionZ, + MSEHasGuidByte3, + MSEHasGuidByte6, + MSEHasSplineElevation, + MSEHasSpline, + MSEHasOrientation, + MSEHasGuidByte7, + MSEHasMovementFlags, + MSEHasGuidByte5, + MSEHasFallData, + MSEHasMovementFlags2, + MSEHasTransportData, + MSEHasTimestamp, + MSEHasGuidByte4, + MSEHasGuidByte1, + MSEZeroBit, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEHasPitch, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte5, + MSEHasTransportTime2, + MSEHasTransportTime3, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte2, + MSEMovementFlags, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte7, + MSETransportGuidByte4, + MSETransportGuidByte7, + MSETransportTime, + MSETransportSeat, + MSETransportPositionZ, + MSETransportTime3, + MSETransportGuidByte2, + MSETransportGuidByte0, + MSETransportPositionY, + MSETransportGuidByte1, + MSETransportGuidByte3, + MSETransportTime2, + MSETransportPositionX, + MSETransportOrientation, + MSETransportGuidByte5, + MSETransportGuidByte6, + MSETimestamp, + MSEOrientation, + MSEPitch, + MSESplineElevation, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallVerticalSpeed, + MSEFallTime, + MSEEnd, +}; + +MovementStatusElements const MovementStopStrafe[] = +{ + MSEPositionY, + MSEPositionZ, + MSEPositionX, + MSEHasPitch, + MSEHasTimestamp, + MSEHasGuidByte2, + MSEHasFallData, + MSEHasGuidByte7, + MSEHasSplineElevation, + MSEHasGuidByte3, + MSEHasOrientation, + MSEHasMovementFlags2, + MSEHasTransportData, + MSEHasMovementFlags, + MSEHasSpline, + MSEHasGuidByte0, + MSEZeroBit, + MSEHasGuidByte6, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte5, + MSEHasTransportTime2, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte3, + MSEHasTransportTime3, + MSEMovementFlags, + MSEHasFallDirection, + MSEMovementFlags2, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte0, + MSETransportSeat, + MSETransportGuidByte6, + MSETransportPositionZ, + MSETransportTime3, + MSETransportGuidByte1, + MSETransportGuidByte3, + MSETransportGuidByte2, + MSETransportGuidByte4, + MSETransportGuidByte5, + MSETransportTime, + MSETransportOrientation, + MSETransportPositionX, + MSETransportGuidByte0, + MSETransportPositionY, + MSETransportTime2, + MSETransportGuidByte7, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallTime, + MSEFallVerticalSpeed, + MSESplineElevation, + MSEOrientation, + MSEPitch, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const MovementStopTurn[] = +{ + MSEPositionX, + MSEPositionZ, + MSEPositionY, + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEHasFallData, + MSEZeroBit, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasSpline, + MSEHasMovementFlags, + MSEHasGuidByte2, + MSEHasGuidByte6, + MSEHasPitch, + MSEHasTransportData, + MSEHasGuidByte3, + MSEHasSplineElevation, + MSEHasTimestamp, + MSEHasMovementFlags2, + MSEHasOrientation, + MSEHasGuidByte7, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte7, + MSEHasTransportTime3, + MSEHasTransportGuidByte4, + MSEHasTransportTime2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasFallDirection, + MSEMovementFlags, + MSEMovementFlags2, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte5, + MSESplineElevation, + MSETransportPositionX, + MSETransportGuidByte5, + MSETransportSeat, + MSETransportGuidByte2, + MSETransportGuidByte3, + MSETransportOrientation, + MSETransportTime2, + MSETransportTime3, + MSETransportGuidByte7, + MSETransportGuidByte1, + MSETransportGuidByte0, + MSETransportGuidByte4, + MSETransportPositionY, + MSETransportPositionZ, + MSETransportTime, + MSETransportGuidByte6, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSETimestamp, + MSEPitch, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementStartAscend[] = +{ + MSEPositionX, + MSEPositionY, + MSEPositionZ, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte7, + MSEZeroBit, + MSEHasGuidByte5, + MSEHasTransportData, + MSEHasGuidByte2, + MSEHasSplineElevation, + MSEHasFallData, + MSEHasSpline, + MSEHasGuidByte3, + MSEHasMovementFlags2, + MSEHasGuidByte6, + MSEHasMovementFlags, + MSEHasPitch, + MSEHasTimestamp, + MSEHasOrientation, + MSEHasGuidByte4, + MSEMovementFlags, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte4, + MSEHasTransportTime2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte7, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte4, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte7, + MSETransportGuidByte3, + MSETransportGuidByte5, + MSETransportGuidByte4, + MSETransportSeat, + MSETransportGuidByte2, + MSETransportOrientation, + MSETransportPositionY, + MSETransportGuidByte7, + MSETransportTime2, + MSETransportPositionZ, + MSETransportTime3, + MSETransportGuidByte6, + MSETransportTime, + MSETransportGuidByte0, + MSETransportGuidByte1, + MSETransportPositionX, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + MSEFallVerticalSpeed, + MSEOrientation, + MSEPitch, + MSETimestamp, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementStartDescend[] = +{ + MSEPositionY, + MSEPositionZ, + MSEPositionX, + MSEHasGuidByte0, + MSEHasPitch, + MSEHasFallData, + MSEHasGuidByte4, + MSEHasOrientation, + MSEHasTimestamp, + MSEHasMovementFlags2, + MSEHasMovementFlags, + MSEHasGuidByte6, + MSEZeroBit, + MSEHasGuidByte1, + MSEHasTransportData, + MSEHasSpline, + MSEHasSplineElevation, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportTime2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte5, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte3, + MSEPitch, + MSETransportPositionZ, + MSETransportSeat, + MSETransportTime3, + MSETransportGuidByte6, + MSETransportTime2, + MSETransportGuidByte1, + MSETransportTime, + MSETransportGuidByte4, + MSETransportPositionY, + MSETransportPositionX, + MSETransportGuidByte7, + MSETransportGuidByte3, + MSETransportGuidByte5, + MSETransportGuidByte2, + MSETransportOrientation, + MSETransportGuidByte0, + MSEFallTime, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallVerticalSpeed, + MSETimestamp, + MSEOrientation, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementStartSwim[] = +{ + MSEPositionZ, + MSEPositionX, + MSEPositionY, + MSEHasGuidByte3, + MSEHasSplineElevation, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEZeroBit, + MSEHasPitch, + MSEHasGuidByte0, + MSEHasOrientation, + MSEHasMovementFlags, + MSEHasFallData, + MSEHasGuidByte5, + MSEHasTransportData, + MSEHasMovementFlags2, + MSEHasTimestamp, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasSpline, + MSEHasGuidByte2, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte0, + MSEHasTransportTime2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasTransportTime3, + MSEMovementFlags, + MSEHasFallDirection, + MSEMovementFlags2, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte7, + MSEPitch, + MSETransportTime2, + MSETransportGuidByte2, + MSETransportPositionY, + MSETransportGuidByte3, + MSETransportTime, + MSETransportPositionX, + MSETransportOrientation, + MSETransportTime3, + MSETransportGuidByte6, + MSETransportGuidByte5, + MSETransportGuidByte4, + MSETransportPositionZ, + MSETransportGuidByte1, + MSETransportGuidByte7, + MSETransportGuidByte0, + MSETransportSeat, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSEOrientation, + MSETimestamp, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementStopSwim[] = +{ + MSEPositionX, + MSEPositionY, + MSEPositionZ, + MSEHasSpline, + MSEHasPitch, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEHasGuidByte7, + MSEHasSplineElevation, + MSEHasMovementFlags, + MSEHasGuidByte4, + MSEHasMovementFlags2, + MSEHasGuidByte2, + MSEHasGuidByte6, + MSEHasTransportData, + MSEHasOrientation, + MSEZeroBit, + MSEHasTimestamp, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasFallData, + MSEHasTransportTime3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte0, + MSEHasTransportTime2, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte5, + MSEMovementFlags, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte2, + MSETransportTime3, + MSETransportGuidByte4, + MSETransportTime, + MSETransportPositionZ, + MSETransportSeat, + MSETransportGuidByte3, + MSETransportGuidByte2, + MSETransportPositionY, + MSETransportGuidByte7, + MSETransportGuidByte1, + MSETransportGuidByte6, + MSETransportGuidByte5, + MSETransportTime2, + MSETransportPositionX, + MSETransportGuidByte0, + MSETransportOrientation, + MSEFallVerticalSpeed, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallTime, + MSETimestamp, + MSEPitch, + MSEOrientation, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementStopAscend[] = +{ + MSEPositionZ, + MSEPositionY, + MSEPositionX, + MSEHasGuidByte3, + MSEHasGuidByte2, + MSEHasFallData, + MSEHasGuidByte7, + MSEHasOrientation, + MSEHasPitch, + MSEHasSpline, + MSEZeroBit, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasMovementFlags, + MSEHasGuidByte0, + MSEHasGuidByte6, + MSEHasSplineElevation, + MSEHasTransportData, + MSEHasMovementFlags2, + MSEHasTimestamp, + MSEHasGuidByte5, + MSEHasTransportTime2, + MSEHasTransportTime3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte7, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte6, + MSETransportGuidByte5, + MSETransportPositionY, + MSETransportGuidByte7, + MSETransportGuidByte2, + MSETransportGuidByte6, + MSETransportTime2, + MSETransportTime3, + MSETransportOrientation, + MSETransportGuidByte3, + MSETransportGuidByte4, + MSETransportSeat, + MSETransportGuidByte1, + MSETransportTime, + MSETransportGuidByte0, + MSETransportPositionX, + MSETransportPositionZ, + MSEFallTime, + MSEFallVerticalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEPitch, + MSESplineElevation, + MSETimestamp, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementStopPitch[] = +{ + MSEPositionX, + MSEPositionZ, + MSEPositionY, + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEHasFallData, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasPitch, + MSEHasSpline, + MSEHasOrientation, + MSEZeroBit, + MSEHasMovementFlags2, + MSEHasSplineElevation, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasTimestamp, + MSEHasTransportData, + MSEHasMovementFlags, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte3, + MSEHasTransportTime2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte1, + MSEHasFallDirection, + MSEMovementFlags2, + MSEMovementFlags, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte5, + MSEGuidByte2, + MSETimestamp, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSETransportGuidByte5, + MSETransportGuidByte2, + MSETransportTime2, + MSETransportPositionX, + MSETransportOrientation, + MSETransportGuidByte6, + MSETransportGuidByte3, + MSETransportGuidByte1, + MSETransportPositionZ, + MSETransportTime3, + MSETransportGuidByte0, + MSETransportGuidByte4, + MSETransportTime, + MSETransportPositionY, + MSETransportSeat, + MSETransportGuidByte7, + MSESplineElevation, + MSEOrientation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementStartPitchDown[] = +{ + MSEPositionX, + MSEPositionZ, + MSEPositionY, + MSEHasMovementFlags, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasPitch, + MSEZeroBit, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasTimestamp, + MSEHasSplineElevation, + MSEHasMovementFlags2, + MSEHasTransportData, + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEHasSpline, + MSEHasOrientation, + MSEHasFallData, + MSEHasGuidByte2, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte5, + MSEHasTransportTime3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportTime2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte2, + MSEMovementFlags2, + MSEHasFallDirection, + MSEMovementFlags, + MSEGuidByte3, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte2, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte1, + MSETransportTime3, + MSETransportGuidByte3, + MSETransportTime2, + MSETransportGuidByte5, + MSETransportGuidByte1, + MSETransportPositionY, + MSETransportGuidByte6, + MSETransportGuidByte4, + MSETransportTime, + MSETransportPositionZ, + MSETransportPositionX, + MSETransportGuidByte0, + MSETransportSeat, + MSETransportGuidByte2, + MSETransportGuidByte7, + MSETransportOrientation, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSEPitch, + MSEOrientation, + MSESplineElevation, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const MovementStartPitchUp[] = +{ + MSEPositionZ, + MSEPositionY, + MSEPositionX, + MSEHasGuidByte4, + MSEHasMovementFlags, + MSEHasMovementFlags2, + MSEHasSpline, + MSEHasGuidByte2, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEZeroBit, + MSEHasSplineElevation, + MSEHasFallData, + MSEHasGuidByte0, + MSEHasTransportData, + MSEHasGuidByte1, + MSEHasGuidByte5, + MSEHasPitch, + MSEHasTimestamp, + MSEHasOrientation, + MSEHasGuidByte7, + MSEMovementFlags2, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasTransportTime2, + MSEHasTransportGuidByte4, + MSEHasTransportTime3, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte2, + MSETransportPositionX, + MSETransportGuidByte1, + MSETransportGuidByte3, + MSETransportGuidByte2, + MSETransportGuidByte0, + MSETransportTime, + MSETransportPositionZ, + MSETransportOrientation, + MSETransportGuidByte7, + MSETransportTime2, + MSETransportSeat, + MSETransportGuidByte6, + MSETransportGuidByte5, + MSETransportTime3, + MSETransportPositionY, + MSETransportGuidByte4, + MSEFallTime, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallVerticalSpeed, + MSEOrientation, + MSESplineElevation, + MSEPitch, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const MoveChngTransport[]= +{ + MSEPositionY, + MSEPositionX, + MSEPositionZ, + MSEHasGuidByte4, + MSEHasGuidByte0, + MSEHasGuidByte2, + MSEHasTransportData, + MSEHasSpline, + MSEHasOrientation, + MSEHasGuidByte6, + MSEHasTimestamp, + MSEHasGuidByte5, + MSEHasGuidByte7, + MSEHasPitch, + MSEZeroBit, + MSEHasGuidByte3, + MSEHasSplineElevation, + MSEHasGuidByte1, + MSEHasFallData, + MSEHasMovementFlags, + MSEHasMovementFlags2, + MSEHasTransportGuidByte3, + MSEHasTransportTime3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEHasTransportTime2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEMovementFlags, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte7, + MSEGuidByte5, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte3, + MSETransportPositionY, + MSETransportSeat, + MSETransportGuidByte1, + MSETransportGuidByte0, + MSETransportGuidByte2, + MSETransportGuidByte3, + MSETransportGuidByte6, + MSETransportPositionZ, + MSETransportPositionX, + MSETransportTime3, + MSETransportTime, + MSETransportGuidByte7, + MSETransportGuidByte5, + MSETransportGuidByte4, + MSETransportOrientation, + MSETransportTime2, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSEOrientation, + MSEPitch, + MSESplineElevation, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const MoveSplineDone[] = +{ + MSEPositionY, + MSEPositionX, + MSEPositionZ, + MSEHasGuidByte6, + MSEHasOrientation, + MSEHasFallData, + MSEHasTimestamp, + MSEHasGuidByte2, + MSEHasSplineElevation, + MSEHasGuidByte4, + MSEHasTransportData, + MSEHasGuidByte3, + MSEHasMovementFlags, + MSEHasGuidByte0, + MSEZeroBit, + MSEHasGuidByte1, + MSEHasGuidByte5, + MSEHasPitch, + MSEHasSpline, + MSEHasMovementFlags2, + MSEHasGuidByte7, + + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportTime2, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportGuidByte0, + + MSEHasFallDirection, + MSEMovementFlags2, + MSEMovementFlags, + + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte3, + + MSEFallVerticalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + + MSEPitch, + MSEOrientation, + + MSETransportGuidByte1, + MSETransportTime3, + MSETransportGuidByte7, + MSETransportTime, + MSETransportPositionY, + MSETransportPositionX, + MSETransportPositionZ, + MSETransportSeat, + MSETransportOrientation, + MSETransportGuidByte0, + MSETransportTime2, + MSETransportGuidByte2, + MSETransportGuidByte3, + MSETransportGuidByte5, + MSETransportGuidByte6, + MSETransportGuidByte4, + + MSETimestamp, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MoveNotActiveMover[] = +{ + MSEPositionZ, + MSEPositionX, + MSEPositionY, + MSEHasMovementFlags2, + MSEHasTransportData, + MSEHasGuidByte6, + MSEHasSplineElevation, + MSEHasGuidByte3, + MSEZeroBit, + MSEHasTimestamp, + MSEHasGuidByte0, + MSEHasOrientation, + MSEHasGuidByte5, + MSEHasPitch, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasSpline, + MSEHasGuidByte2, + MSEHasFallData, + MSEHasMovementFlags, + + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte7, + MSEHasTransportTime2, + MSEHasTransportGuidByte3, + + MSEHasFallDirection, + MSEMovementFlags, + MSEMovementFlags2, + + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte3, + + MSEFallVerticalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + + MSETransportTime3, + MSETransportGuidByte1, + MSETransportTime2, + MSETransportOrientation, + MSETransportGuidByte0, + MSETransportSeat, + MSETransportGuidByte4, + MSETransportGuidByte6, + MSETransportGuidByte3, + MSETransportGuidByte5, + MSETransportPositionY, + MSETransportPositionX, + MSETransportGuidByte2, + MSETransportPositionZ, + MSETransportGuidByte7, + MSETransportTime, + + MSETimestamp, + MSESplineElevation, + MSEPitch, + MSEOrientation, + + MSEEnd, +}; + +MovementStatusElements const DismissControlledVehicle[] = +{ + MSEPositionY, + MSEPositionZ, + MSEPositionX, + MSEHasSplineElevation, + MSEHasFallData, + MSEHasTransportData, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasMovementFlags2, + MSEHasGuidByte2, + MSEHasOrientation, + MSEHasGuidByte0, + MSEHasGuidByte6, + MSEHasPitch, + MSEHasTimestamp, + MSEHasGuidByte1, + MSEZeroBit, + MSEHasSpline, + MSEHasGuidByte3, + MSEHasMovementFlags, + MSEHasGuidByte5, + + MSEHasTransportGuidByte5, + MSEHasTransportTime3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportTime2, + + MSEMovementFlags2, + MSEHasFallDirection, + MSEMovementFlags, + + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte2, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte0, + + MSETimestamp, + + MSETransportTime3, + MSETransportGuidByte4, + MSETransportGuidByte7, + MSETransportTime2, + MSETransportGuidByte6, + MSETransportTime, + MSETransportPositionZ, + MSETransportGuidByte0, + MSETransportPositionX, + MSETransportGuidByte3, + MSETransportSeat, + MSETransportPositionY, + MSETransportOrientation, + MSETransportGuidByte1, + MSETransportGuidByte5, + MSETransportGuidByte2, + + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallVerticalSpeed, + + MSEOrientation, + MSESplineElevation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MoveUpdateTeleport[] = +{ + MSEPositionZ, + MSEPositionY, + MSEPositionX, + MSEHasOrientation, + + MSEHasSpline, + MSEHasMovementFlags, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasFallData, + MSEHasGuidByte0, + MSEHasTransportData, + MSEHasGuidByte5, + + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte0, + MSEHasTransportTime2, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte6, + MSEHasTransportTime3, + MSEHasTransportGuidByte2, + + MSEZeroBit, + + MSEHasGuidByte7, + MSEHasGuidByte3, + MSEHasPitch, + MSEHasMovementFlags2, + MSEHasTimestamp, + + MSEHasFallDirection, + MSEMovementFlags2, + MSEHasSplineElevation, + MSEMovementFlags, + MSEHasGuidByte1, + + MSEGuidByte7, + MSETransportGuidByte3, + MSETransportGuidByte4, + MSETransportOrientation, + MSETransportTime3, + MSETransportGuidByte1, + MSETransportTime2, + MSETransportPositionZ, + MSETransportGuidByte7, + MSETransportGuidByte0, + MSETransportGuidByte6, + MSETransportGuidByte5, + MSETransportGuidByte2, + MSETransportSeat, + MSETransportTime, + MSETransportPositionY, + MSETransportPositionX, + + MSEGuidByte6, + MSEPitch, + MSESplineElevation, + MSEOrientation, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte1, + + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallVerticalSpeed, + + MSEGuidByte5, + MSEGuidByte4, + MSETimestamp, + MSEGuidByte0, + + MSEEnd, +}; + +MovementStatusElements const MovementSetRunMode[] = +{ + MSEPositionY, + MSEPositionX, + MSEPositionZ, + MSEHasTimestamp, + MSEHasMovementFlags2, + MSEHasGuidByte1, + MSEHasSpline, + MSEHasMovementFlags, + MSEHasGuidByte7, + MSEHasTransportData, + MSEZeroBit, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasSplineElevation, + MSEHasGuidByte5, + MSEHasPitch, + MSEHasGuidByte6, + MSEHasGuidByte4, + MSEHasFallData, + MSEHasOrientation, + MSEHasGuidByte2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte4, + MSEHasTransportTime3, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasTransportTime2, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte2, + MSEHasFallDirection, + MSEMovementFlags2, + MSEMovementFlags, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte2, + MSEPitch, + MSETransportTime2, + MSETransportGuidByte3, + MSETransportPositionX, + MSETransportSeat, + MSETransportGuidByte5, + MSETransportGuidByte1, + MSETransportPositionZ, + MSETransportGuidByte2, + MSETransportGuidByte7, + MSETransportOrientation, + MSETransportGuidByte4, + MSETransportTime, + MSETransportTime3, + MSETransportGuidByte0, + MSETransportPositionY, + MSETransportGuidByte6, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallTime, + MSEFallVerticalSpeed, + MSESplineElevation, + MSETimestamp, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementSetWalkMode[] = +{ + MSEPositionY, + MSEPositionX, + MSEPositionZ, + MSEHasGuidByte6, + MSEHasSpline, + MSEHasTimestamp, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasMovementFlags, + MSEHasPitch, + MSEHasGuidByte7, + MSEHasSplineElevation, + MSEHasGuidByte4, + MSEHasOrientation, + MSEHasTransportData, + MSEHasGuidByte2, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEZeroBit, + MSEHasMovementFlags2, + MSEHasFallData, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte3, + MSEHasTransportTime2, + MSEHasTransportGuidByte5, + MSEHasTransportTime3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte7, + MSEHasFallDirection, + MSEMovementFlags, + MSEMovementFlags2, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte1, + MSETransportGuidByte2, + MSETransportGuidByte5, + MSETransportSeat, + MSETransportPositionZ, + MSETransportGuidByte3, + MSETransportGuidByte6, + MSETransportGuidByte0, + MSETransportTime, + MSETransportGuidByte4, + MSETransportTime2, + MSETransportOrientation, + MSETransportPositionX, + MSETransportTime3, + MSETransportGuidByte7, + MSETransportPositionY, + MSETransportGuidByte1, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSESplineElevation, + MSEPitch, + MSETimestamp, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementSetCanFly[] = +{ + MSEPositionZ, + MSEPositionX, + MSEPositionY, + MSEHasTransportData, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasFallData, + MSEHasGuidByte0, + MSEHasMovementFlags, + MSEHasGuidByte3, + MSEHasMovementFlags2, + MSEHasGuidByte5, + MSEHasTimestamp, + MSEHasSplineElevation, + MSEHasSpline, + MSEHasOrientation, + MSEHasGuidByte7, + MSEZeroBit, + MSEHasPitch, + MSEHasTransportGuidByte3, + MSEHasTransportTime2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportTime3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte5, + MSEMovementFlags2, + MSEHasFallDirection, + MSEMovementFlags, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte5, + MSEGuidByte1, + MSEGuidByte3, + MSEGuidByte6, + MSETransportPositionZ, + MSETransportGuidByte3, + MSETransportGuidByte5, + MSETransportGuidByte4, + MSETransportSeat, + MSETransportPositionX, + MSETransportGuidByte2, + MSETransportTime2, + MSETransportPositionY, + MSETransportGuidByte1, + MSETransportTime, + MSETransportGuidByte7, + MSETransportGuidByte0, + MSETransportOrientation, + MSETransportGuidByte6, + MSETransportTime3, + MSESplineElevation, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallVerticalSpeed, + MSEFallTime, + MSEPitch, + MSETimestamp, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementSetCanTransitionBetweenSwimAndFlyAck[] = +{ + MSEPositionZ, + MSEPositionY, + MSECounter, + MSEPositionX, + MSEHasGuidByte3, + MSEHasOrientation, + MSEHasTransportData, + MSEHasMovementFlags, + MSEHasMovementFlags2, + MSEHasSplineElevation, + MSEHasTimestamp, + MSEHasSpline, + MSEZeroBit, + MSEHasFallData, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEHasPitch, + MSEHasGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte2, + MSEHasTransportTime2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte5, + MSEHasTransportTime3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte1, + MSEMovementFlags2, + MSEHasFallDirection, + MSEMovementFlags, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte7, + MSEGuidByte6, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallVerticalSpeed, + MSETransportPositionY, + MSETransportPositionZ, + MSETransportGuidByte5, + MSETransportGuidByte1, + MSETransportGuidByte4, + MSETransportTime, + MSETransportSeat, + MSETransportGuidByte3, + MSETransportGuidByte0, + MSETransportGuidByte2, + MSETransportGuidByte7, + MSETransportPositionX, + MSETransportTime2, + MSETransportGuidByte6, + MSETransportOrientation, + MSETransportTime3, + MSEPitch, + MSEOrientation, + MSETimestamp, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementUpdateSwimSpeed[] = +{ + MSEHasMovementFlags, + MSEHasGuidByte2, + MSEMovementFlags, + MSEHasGuidByte3, + MSEZeroBit, + MSEHasGuidByte7, + MSEHasFallDirection, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasOrientation, + MSEHasGuidByte1, + MSETransportGuidByte2, + MSETransportPositionX, + MSETransportGuidByte6, + MSETransportOrientation, + MSETransportGuidByte0, + MSETransportGuidByte4, + MSETransportPositionY, + MSETransportTime, + MSETransportGuidByte1, + MSETransportGuidByte7, + MSETransportPositionZ, + MSETransportSeat, + MSETransportGuidByte3, + MSETransportGuidByte5, + MSEPositionX, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallTime, + MSEFallVerticalSpeed, + MSEGuidByte7, + MSETimestamp, + MSEPositionY, + MSEPositionZ, + MSEExtraElement, + MSEGuidByte4, + MSEOrientation, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte0, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte5, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementUpdateRunSpeed[] = +{ + MSEPositionZ, + MSEPositionX, + MSEPositionY, + MSEExtraElement, + MSEHasGuidByte6, + MSEHasMovementFlags2, + MSEHasPitch, + MSEHasGuidByte2, + MSEHasGuidByte5, + MSEHasSplineElevation, + MSEHasSpline, + MSEHasMovementFlags, + MSEHasTimestamp, + MSEHasGuidByte1, + MSEMovementFlags2, + MSEHasGuidByte3, + MSEMovementFlags, + MSEHasGuidByte7, + MSEHasGuidByte0, + MSEHasOrientation, + MSEHasTransportData, + MSEHasTransportGuidByte5, + MSEHasTransportTime2, + MSEHasTransportTime3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte0, + MSEHasFallData, + MSEHasFallDirection, + MSEHasGuidByte4, + MSEZeroBit, + MSETransportGuidByte4, + MSETransportGuidByte5, + MSETransportPositionX, + MSETransportOrientation, + MSETransportGuidByte1, + MSETransportGuidByte0, + MSETransportGuidByte6, + MSETransportTime, + MSETransportGuidByte7, + MSETransportSeat, + MSETransportTime2, + MSETransportPositionY, + MSETransportGuidByte3, + MSETransportGuidByte2, + MSETransportTime3, + MSETransportPositionZ, + MSETimestamp, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSEPitch, + MSEGuidByte6, + MSESplineElevation, + MSEGuidByte5, + MSEGuidByte7, + MSEGuidByte4, + MSEOrientation, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte1, + MSEEnd, +}; + +MovementStatusElements const MovementUpdateFlightSpeed[] = +{ + MSEPositionY, + MSEExtraElement, + MSEPositionX, + MSEPositionZ, + MSEHasMovementFlags, + MSEHasGuidByte4, + MSEZeroBit, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEMovementFlags, + MSEHasGuidByte2, + MSEHasOrientation, + MSEHasGuidByte7, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEHasFallDirection, + MSEHasGuidByte0, + MSEPitch, + MSEGuidByte0, + MSEGuidByte5, + MSETransportOrientation, + MSETransportTime, + MSETransportGuidByte5, + MSETransportGuidByte4, + MSETransportGuidByte6, + MSETransportPositionZ, + MSETransportGuidByte7, + MSETransportGuidByte0, + MSETransportGuidByte2, + MSETransportGuidByte3, + MSETransportPositionY, + MSETransportGuidByte1, + MSETransportSeat, + MSETransportPositionX, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSEGuidByte1, + MSEGuidByte6, + MSETimestamp, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte4, + MSEOrientation, + MSEGuidByte3, + MSEEnd, +}; + +MovementStatusElements const MovementUpdateCollisionHeight[] = +{ + MSEPositionZ, + MSEExtraElement, + MSEPositionX, + MSEPositionY, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte2, + MSEHasGuidByte3, + MSEHasOrientation, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEZeroBit, + MSEHasGuidByte2, + MSEHasMovementFlags, + MSEHasFallDirection, + MSEHasGuidByte1, + MSEMovementFlags, + MSEGuidByte3, + MSETransportGuidByte7, + MSETransportTime, + MSETransportGuidByte4, + MSETransportGuidByte5, + MSETransportOrientation, + MSETransportPositionX, + MSETransportGuidByte6, + MSETransportGuidByte0, + MSETransportPositionY, + MSETransportGuidByte2, + MSETransportPositionZ, + MSETransportGuidByte3, + MSETransportGuidByte1, + MSETransportSeat, + MSEPitch, + MSEGuidByte6, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallVerticalSpeed, + MSEFallTime, + MSEGuidByte7, + MSEOrientation, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte4, + MSETimestamp, + MSEGuidByte2, + MSEGuidByte1, + MSEEnd, +}; + +MovementStatusElements const MovementForceRunSpeedChangeAck[] = +{ + MSECounter, + MSEPositionX, + MSEExtraElement, + MSEPositionZ, + MSEPositionY, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasGuidByte1, + MSEHasGuidByte7, + MSEHasOrientation, + MSEHasFallData, + MSEHasGuidByte0, + MSEHasSpline, + MSEHasTransportData, + MSEHasTimestamp, + MSEHasMovementFlags2, + MSEHasGuidByte6, + MSEZeroBit, + MSEHasSplineElevation, + MSEHasPitch, + MSEHasGuidByte5, + MSEHasMovementFlags, + MSEHasGuidByte3, + MSEHasTransportTime3, + MSEHasTransportGuidByte5, + MSEHasTransportTime2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte4, + MSEMovementFlags, + MSEHasFallDirection, + MSEMovementFlags2, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte3, + MSEGuidByte5, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte0, + MSETransportPositionZ, + MSETransportGuidByte6, + MSETransportGuidByte1, + MSETransportPositionY, + MSETransportGuidByte0, + MSETransportGuidByte5, + MSETransportTime2, + MSETransportPositionX, + MSETransportTime, + MSETransportGuidByte7, + MSETransportOrientation, + MSETransportGuidByte3, + MSETransportTime3, + MSETransportGuidByte2, + MSETransportSeat, + MSETransportGuidByte4, + MSEFallVerticalSpeed, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallTime, + MSESplineElevation, + MSEPitch, + MSETimestamp, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementSetCollisionHeightAck[] = +{ + MSEExtraElement, + MSEPositionX, + MSEPositionZ, + MSECounter, + MSEPositionY, + MSEHasGuidByte6, + MSEHasGuidByte4, + MSEZeroBit, + MSEZeroBit, + MSEHasPitch, + MSEHasGuidByte5, + MSEZeroBit, + MSEHasGuidByte2, + MSEHasGuidByte1, + MSEHasFallData, + MSEHasGuidByte3, + MSEHasSpline, + MSEHasGuidByte7, + MSEHasMovementFlags, + MSEHasTransportData, + MSEHasTimestamp, + MSEHasSplineElevation, + MSEHasMovementFlags2, + MSEHasOrientation, + MSEHasGuidByte0, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte3, + MSEHasTransportTime2, + MSEHasTransportTime3, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte7, + MSEGuidByte6, + MSEGuidByte2, + MSEGuidByte4, + MSETransportPositionX, + MSETransportGuidByte4, + MSETransportTime2, + MSETransportGuidByte0, + MSETransportOrientation, + MSETransportPositionY, + MSETransportGuidByte7, + MSETransportSeat, + MSETransportGuidByte5, + MSETransportGuidByte2, + MSETransportTime, + MSETransportGuidByte6, + MSETransportGuidByte3, + MSETransportGuidByte1, + MSETransportTime3, + MSETransportPositionZ, + MSEFallVerticalSpeed, + MSEFallTime, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSETimestamp, + MSESplineElevation, + MSEOrientation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementForceFlightSpeedChangeAck[] = +{ + MSECounter, + MSEPositionZ, + MSEPositionX, + MSEPositionY, + MSEExtraElement, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEZeroBit, + MSEHasMovementFlags, + MSEHasSplineElevation, + MSEHasGuidByte3, + MSEHasMovementFlags2, + MSEHasGuidByte7, + MSEHasTransportData, + MSEHasGuidByte0, + MSEHasFallData, + MSEHasTimestamp, + MSEHasPitch, + MSEHasSpline, + MSEHasOrientation, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEHasGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte7, + MSEHasTransportTime2, + MSEHasTransportGuidByte0, + MSEHasTransportTime3, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte4, + MSEHasFallDirection, + MSEMovementFlags2, + MSEMovementFlags, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte4, + MSETransportGuidByte6, + MSETransportGuidByte0, + MSETransportSeat, + MSETransportTime2, + MSETransportOrientation, + MSETransportGuidByte1, + MSETransportGuidByte5, + MSETransportTime3, + MSETransportGuidByte2, + MSETransportPositionZ, + MSETransportGuidByte7, + MSETransportGuidByte3, + MSETransportGuidByte4, + MSETransportPositionX, + MSETransportTime, + MSETransportPositionY, + MSETimestamp, + MSESplineElevation, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + MSEFallVerticalSpeed, + MSEPitch, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementSetCanFlyAck[] = +{ + MSEPositionY, + MSECounter, + MSEPositionX, + MSEPositionZ, + MSEHasGuidByte3, + MSEHasTimestamp, + MSEHasGuidByte4, + MSEHasGuidByte0, + MSEHasOrientation, + MSEHasFallData, + MSEHasGuidByte2, + MSEHasGuidByte5, + MSEHasSplineElevation, + MSEHasMovementFlags2, + MSEZeroBit, + MSEHasGuidByte7, + MSEHasSpline, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasMovementFlags, + MSEHasTransportData, + MSEHasPitch, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportTime2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte7, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte5, + MSETransportTime2, + MSETransportGuidByte6, + MSETransportTime, + MSETransportTime3, + MSETransportGuidByte7, + MSETransportPositionZ, + MSETransportGuidByte3, + MSETransportPositionY, + MSETransportGuidByte5, + MSETransportPositionX, + MSETransportGuidByte2, + MSETransportOrientation, + MSETransportSeat, + MSETransportGuidByte1, + MSETransportGuidByte0, + MSETransportGuidByte4, + MSEFallTime, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSEPitch, + MSEOrientation, + MSETimestamp, + MSESplineElevation, + MSEEnd, +}; + +MovementStatusElements const MovementForceSwimSpeedChangeAck[] = +{ + MSEPositionX, + MSECounter, + MSEExtraElement, + MSEPositionY, + MSEPositionZ, + MSEHasGuidByte4, + MSEHasOrientation, + MSEHasPitch, + MSEHasTransportData, + MSEHasMovementFlags, + MSEHasMovementFlags2, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasFallData, + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasTimestamp, + MSEZeroBit, + MSEHasGuidByte5, + MSEHasGuidByte6, + MSEHasSplineElevation, + MSEHasSpline, + MSEHasGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte3, + MSEHasTransportTime2, + MSEHasTransportTime3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEMovementFlags2, + MSEHasFallDirection, + MSEMovementFlags, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte6, + MSEGuidByte5, + MSEGuidByte1, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte7, + MSETransportGuidByte0, + MSETransportTime3, + MSETransportTime2, + MSETransportPositionX, + MSETransportGuidByte7, + MSETransportSeat, + MSETransportPositionY, + MSETransportGuidByte5, + MSETransportPositionZ, + MSETransportOrientation, + MSETransportTime, + MSETransportGuidByte2, + MSETransportGuidByte6, + MSETransportGuidByte3, + MSETransportGuidByte1, + MSETransportGuidByte4, + MSEFallTime, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallVerticalSpeed, + MSEOrientation, + MSEPitch, + MSESplineElevation, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const MovementForceWalkSpeedChangeAck[] = +{ + MSEPositionZ, + MSEPositionY, + MSEExtraElement, + MSEPositionX, + MSECounter, + MSEHasGuidByte0, + MSEHasMovementFlags2, + MSEHasTimestamp, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEHasMovementFlags, + MSEHasFallData, + MSEHasOrientation, + MSEHasSpline, + MSEZeroBit, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasSplineElevation, + MSEHasTransportData, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasPitch, + MSEHasTransportTime2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportTime3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte3, + MSEMovementFlags, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte0, + MSEFallVerticalSpeed, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallTime, + MSETransportPositionZ, + MSETransportGuidByte7, + MSETransportGuidByte5, + MSETransportPositionX, + MSETransportGuidByte0, + MSETransportTime, + MSETransportTime3, + MSETransportPositionY, + MSETransportGuidByte2, + MSETransportGuidByte4, + MSETransportGuidByte1, + MSETransportGuidByte3, + MSETransportOrientation, + MSETransportSeat, + MSETransportGuidByte6, + MSETransportTime2, + MSESplineElevation, + MSETimestamp, + MSEOrientation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementForceRunBackSpeedChangeAck[] = +{ + MSEExtraElement, + MSECounter, + MSEPositionX, + MSEPositionZ, + MSEPositionY, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasTimestamp, + MSEHasTransportData, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEHasOrientation, + MSEHasFallData, + MSEHasMovementFlags2, + MSEHasMovementFlags, + MSEHasGuidByte7, + MSEHasSpline, + MSEHasPitch, + MSEHasGuidByte6, + MSEHasSplineElevation, + MSEZeroBit, + MSEHasTransportGuidByte3, + MSEHasTransportTime2, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte1, + MSEHasTransportTime3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte5, + MSEMovementFlags, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte5, + MSEGuidByte1, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSETransportGuidByte5, + MSETransportSeat, + MSETransportGuidByte6, + MSETransportGuidByte1, + MSETransportGuidByte0, + MSETransportGuidByte2, + MSETransportPositionY, + MSETransportTime3, + MSETransportPositionX, + MSETransportOrientation, + MSETransportGuidByte3, + MSETransportTime, + MSETransportTime2, + MSETransportGuidByte4, + MSETransportPositionZ, + MSETransportGuidByte7, + MSETimestamp, + MSESplineElevation, + MSEOrientation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementUpdateRunBackSpeed[] = +{ + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasGuidByte3, + MSEHasGuidByte6, + MSEHasGuidByte0, + MSEZeroBit, + MSEHasMovementFlags, + MSEHasGuidByte5, + MSEHasOrientation, + MSEMovementFlags, + MSEHasFallDirection, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte0, + MSEHasGuidByte7, + MSETransportPositionX, + MSETransportGuidByte2, + MSETransportGuidByte5, + MSETransportGuidByte4, + MSETransportGuidByte6, + MSETransportGuidByte0, + MSETransportGuidByte3, + MSETransportPositionY, + MSETransportGuidByte7, + MSETransportPositionZ, + MSETransportTime, + MSETransportSeat, + MSETransportGuidByte1, + MSETransportOrientation, + MSEGuidByte4, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSETimestamp, + MSEGuidByte1, + MSEOrientation, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte3, + MSEPositionX, + MSEPositionY, + MSEPitch, + MSEGuidByte7, + MSEExtraElement, + MSEGuidByte2, + MSEGuidByte6, + MSEPositionZ, + MSEEnd, +}; + +MovementStatusElements const MovementUpdateWalkSpeed[] = +{ + MSEHasOrientation, + MSEZeroBit, + MSEHasGuidByte3, + MSEHasGuidByte2, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte5, + MSEHasGuidByte7, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasMovementFlags, + MSEHasGuidByte6, + MSEHasFallDirection, + MSEMovementFlags, + MSEHasGuidByte4, + MSEPitch, + MSETransportGuidByte6, + MSETransportGuidByte0, + MSETransportGuidByte4, + MSETransportGuidByte2, + MSETransportPositionX, + MSETransportGuidByte7, + MSETransportTime, + MSETransportPositionZ, + MSETransportSeat, + MSETransportGuidByte5, + MSETransportOrientation, + MSETransportGuidByte1, + MSETransportPositionY, + MSETransportGuidByte3, + MSEFallVerticalSpeed, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallTime, + MSEGuidByte1, + MSEGuidByte4, + MSEGuidByte2, + MSEGuidByte6, + MSEGuidByte7, + MSETimestamp, + MSEOrientation, + MSEPositionY, + MSEGuidByte0, + MSEPositionZ, + MSEPositionX, + MSEGuidByte3, + MSEGuidByte5, + MSEExtraElement, + MSEEnd, +}; + +MovementStatusElements const ForceMoveRootAck[] = +{ + MSEPositionY, + MSEPositionZ, + MSECounter, + MSEPositionX, + MSEHasGuidByte3, + MSEHasTimestamp, + MSEHasTransportData, + MSEHasPitch, + MSEHasGuidByte2, + MSEHasOrientation, + MSEHasSplineElevation, + MSEHasFallData, + MSEHasSpline, + MSEHasGuidByte4, + MSEHasGuidByte0, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasGuidByte7, + MSEHasMovementFlags2, + MSEHasMovementFlags, + MSEZeroBit, + MSEHasGuidByte5, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte2, + MSEHasTransportTime2, + MSEHasTransportGuidByte4, + MSEHasTransportTime3, + MSEHasTransportGuidByte5, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte6, + MSEGuidByte2, + MSETransportGuidByte5, + MSETransportGuidByte4, + MSETransportOrientation, + MSETransportPositionZ, + MSETransportTime3, + MSETransportTime2, + MSETransportGuidByte7, + MSETransportGuidByte2, + MSETransportGuidByte0, + MSETransportTime, + MSETransportGuidByte6, + MSETransportGuidByte3, + MSETransportPositionX, + MSETransportGuidByte1, + MSETransportPositionY, + MSETransportSeat, + MSETimestamp, + MSEFallVerticalSpeed, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallTime, + MSEOrientation, + MSESplineElevation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const ForceMoveUnrootAck[] = +{ + MSECounter, + MSEPositionZ, + MSEPositionY, + MSEPositionX, + MSEHasGuidByte7, + MSEHasSplineElevation, + MSEHasSpline, + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEZeroBit, + MSEHasTimestamp, + MSEHasMovementFlags, + MSEHasOrientation, + MSEHasPitch, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasTransportData, + MSEHasMovementFlags2, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEHasFallData, + MSEHasGuidByte6, + MSEHasFallDirection, + MSEHasTransportGuidByte0, + MSEHasTransportTime3, + MSEHasTransportGuidByte6, + MSEHasTransportTime2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte1, + MSEMovementFlags2, + MSEMovementFlags, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte6, + MSEGuidByte2, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte3, + MSETransportGuidByte6, + MSETransportPositionZ, + MSETransportGuidByte2, + MSETransportGuidByte3, + MSETransportPositionY, + MSETransportTime3, + MSETransportGuidByte5, + MSETransportSeat, + MSETransportGuidByte0, + MSETransportTime, + MSETransportTime2, + MSETransportGuidByte4, + MSETransportOrientation, + MSETransportPositionX, + MSETransportGuidByte1, + MSETransportGuidByte7, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSETimestamp, + MSESplineElevation, + MSEOrientation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementFallReset[] = +{ + MSEPositionZ, + MSEPositionX, + MSEPositionY, + MSEHasGuidByte1, + MSEHasTimestamp, + MSEHasMovementFlags, + MSEZeroBit, + MSEHasGuidByte6, + MSEHasSplineElevation, + MSEHasPitch, + MSEHasGuidByte3, + MSEHasTransportData, + MSEHasGuidByte2, + MSEHasMovementFlags2, + MSEHasOrientation, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasSpline, + MSEHasGuidByte7, + MSEHasGuidByte0, + MSEHasFallData, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte4, + MSEHasTransportTime2, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte3, + MSEHasFallDirection, + MSEMovementFlags2, + MSEMovementFlags, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte5, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte6, + MSETransportPositionX, + MSETransportGuidByte7, + MSETransportGuidByte2, + MSETransportGuidByte3, + MSETransportGuidByte5, + MSETransportPositionY, + MSETransportPositionZ, + MSETransportSeat, + MSETransportTime2, + MSETransportGuidByte6, + MSETransportTime3, + MSETransportTime, + MSETransportGuidByte0, + MSETransportOrientation, + MSETransportGuidByte4, + MSETransportGuidByte1, + MSEFallVerticalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + MSEOrientation, + MSETimestamp, + MSESplineElevation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementFeatherFallAck[] = +{ + MSEPositionZ, + MSECounter, + MSEPositionY, + MSEPositionX, + MSEZeroBit, + MSEHasGuidByte3, + MSEHasSplineElevation, + MSEHasGuidByte1, + MSEHasPitch, + MSEHasGuidByte2, + MSEHasSpline, + MSEHasTimestamp, + MSEHasGuidByte5, + MSEHasFallData, + MSEHasOrientation, + MSEHasTransportData, + MSEHasGuidByte7, + MSEHasMovementFlags2, + MSEHasGuidByte6, + MSEHasMovementFlags, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportTime3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte5, + MSEHasTransportTime2, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte0, + MSEHasFallDirection, + MSEMovementFlags2, + MSEMovementFlags, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte2, + MSETransportTime3, + MSETransportOrientation, + MSETransportPositionZ, + MSETransportGuidByte7, + MSETransportGuidByte5, + MSETransportGuidByte2, + MSETransportPositionX, + MSETransportGuidByte1, + MSETransportGuidByte6, + MSETransportTime2, + MSETransportTime, + MSETransportPositionY, + MSETransportGuidByte4, + MSETransportGuidByte0, + MSETransportSeat, + MSETransportGuidByte3, + MSETimestamp, + MSESplineElevation, + MSEOrientation, + MSEFallVerticalSpeed, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallTime, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementGravityDisableAck[] = +{ + MSEPositionZ, + MSEPositionY, + MSECounter, + MSEPositionX, + MSEHasGuidByte3, + MSEHasTransportData, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasMovementFlags, + MSEHasOrientation, + MSEHasSpline, + MSEHasGuidByte6, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSEHasSplineElevation, + MSEHasTimestamp, + MSEHasPitch, + MSEHasMovementFlags2, + MSEZeroBit, + MSEHasGuidByte2, + MSEHasFallData, + MSEHasGuidByte1, + MSEHasTransportGuidByte2, + MSEHasTransportTime3, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte4, + MSEHasTransportTime2, + MSEMovementFlags, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte3, + MSEGuidByte5, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte6, + MSETransportPositionZ, + MSETransportGuidByte2, + MSETransportGuidByte5, + MSETransportGuidByte3, + MSETransportGuidByte4, + MSETransportPositionY, + MSETransportTime, + MSETransportSeat, + MSETransportGuidByte6, + MSETransportGuidByte1, + MSETransportGuidByte0, + MSETransportOrientation, + MSETransportTime2, + MSETransportPositionX, + MSETransportGuidByte7, + MSETransportTime3, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + MSEFallVerticalSpeed, + MSEOrientation, + MSESplineElevation, + MSETimestamp, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementGravityEnableAck[] = +{ + MSEPositionZ, + MSEPositionX, + MSECounter, + MSEPositionY, + MSEHasSplineElevation, + MSEHasMovementFlags2, + MSEHasGuidByte6, + MSEHasOrientation, + MSEZeroBit, + MSEHasGuidByte5, + MSEHasSpline, + MSEHasGuidByte3, + MSEHasTransportData, + MSEHasPitch, + MSEHasGuidByte1, + MSEHasTimestamp, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasMovementFlags, + MSEHasFallData, + MSEHasGuidByte0, + MSEHasTransportTime3, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte5, + MSEHasTransportTime2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasFallDirection, + MSEMovementFlags, + MSEMovementFlags2, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte6, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallVerticalSpeed, + MSETransportGuidByte1, + MSETransportPositionX, + MSETransportTime3, + MSETransportOrientation, + MSETransportGuidByte2, + MSETransportGuidByte0, + MSETransportGuidByte7, + MSETransportGuidByte6, + MSETransportSeat, + MSETransportGuidByte3, + MSETransportGuidByte4, + MSETransportPositionZ, + MSETransportTime2, + MSETransportGuidByte5, + MSETransportTime, + MSETransportPositionY, + MSESplineElevation, + MSEOrientation, + MSEPitch, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const MovementHoverAck[] = +{ + MSECounter, + MSEPositionZ, + MSEPositionY, + MSEPositionX, + MSEHasGuidByte4, + MSEHasTransportData, + MSEHasGuidByte2, + MSEHasTimestamp, + MSEHasSpline, + MSEHasMovementFlags, + MSEHasGuidByte1, + MSEHasPitch, + MSEHasGuidByte0, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEHasGuidByte5, + MSEZeroBit, + MSEHasFallData, + MSEHasMovementFlags2, + MSEHasSplineElevation, + MSEHasOrientation, + MSEHasGuidByte3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEHasTransportTime3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte7, + MSEHasTransportTime2, + MSEMovementFlags, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte1, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte0, + MSETimestamp, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + MSEFallVerticalSpeed, + MSEOrientation, + MSETransportGuidByte1, + MSETransportTime3, + MSETransportGuidByte2, + MSETransportGuidByte7, + MSETransportGuidByte3, + MSETransportGuidByte4, + MSETransportSeat, + MSETransportPositionX, + MSETransportPositionZ, + MSETransportOrientation, + MSETransportTime, + MSETransportGuidByte0, + MSETransportPositionY, + MSETransportGuidByte5, + MSETransportTime2, + MSETransportGuidByte6, + MSESplineElevation, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementKnockBackAck[] = +{ + MSEPositionY, + MSEPositionZ, + MSECounter, + MSEPositionX, + MSEHasGuidByte6, + MSEHasOrientation, + MSEHasPitch, + MSEHasSplineElevation, + MSEHasGuidByte3, + MSEHasGuidByte4, + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEHasSpline, + MSEHasGuidByte7, + MSEZeroBit, + MSEHasMovementFlags2, + MSEHasTimestamp, + MSEHasGuidByte0, + MSEHasMovementFlags, + MSEHasTransportData, + MSEHasGuidByte5, + MSEHasFallData, + MSEMovementFlags, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte1, + MSEHasTransportTime2, + MSEHasTransportGuidByte0, + MSEHasTransportTime3, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte7, + MSEMovementFlags2, + MSEHasFallDirection, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte1, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte7, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallTime, + MSEFallVerticalSpeed, + MSETimestamp, + MSETransportPositionY, + MSETransportGuidByte4, + MSETransportTime2, + MSETransportGuidByte7, + MSETransportOrientation, + MSETransportGuidByte6, + MSETransportTime, + MSETransportGuidByte3, + MSETransportGuidByte1, + MSETransportTime3, + MSETransportGuidByte2, + MSETransportPositionZ, + MSETransportGuidByte0, + MSETransportGuidByte5, + MSETransportPositionX, + MSETransportSeat, + MSEPitch, + MSESplineElevation, + MSEOrientation, + MSEEnd, +}; + +MovementStatusElements const MovementWaterWalkAck[] = +{ + MSEPositionY, + MSEPositionZ, + MSECounter, + MSEPositionX, + MSEHasTimestamp, + MSEHasPitch, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSEHasOrientation, + MSEHasGuidByte1, + MSEHasMovementFlags2, + MSEHasGuidByte2, + MSEHasMovementFlags, + MSEHasGuidByte3, + MSEHasTransportData, + MSEHasGuidByte6, + MSEHasFallData, + MSEHasGuidByte4, + MSEZeroBit, + MSEHasSplineElevation, + MSEHasSpline, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEHasTransportTime2, + MSEHasTransportGuidByte3, + MSEHasTransportTime3, + MSEHasTransportGuidByte4, + MSEMovementFlags, + MSEHasFallDirection, + MSEMovementFlags2, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte1, + MSETransportPositionX, + MSETransportGuidByte1, + MSETransportTime3, + MSETransportGuidByte0, + MSETransportOrientation, + MSETransportGuidByte7, + MSETransportPositionY, + MSETransportTime2, + MSETransportTime, + MSETransportGuidByte5, + MSETransportSeat, + MSETransportPositionZ, + MSETransportGuidByte3, + MSETransportGuidByte2, + MSETransportGuidByte6, + MSETransportGuidByte4, + MSESplineElevation, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSEFallTime, + MSEOrientation, + MSETimestamp, + MSEPitch, + MSEEnd, +}; + +MovementStatusElements const MovementUpdateKnockBack[] = +{ + MSEZeroBit, + MSEHasGuidByte4, + MSEHasMovementFlags, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte3, + MSEHasGuidByte5, + MSEHasGuidByte6, + MSEMovementFlags, + MSEHasFallDirection, + MSEHasOrientation, + MSEOrientation, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallCosAngle, + MSEFallTime, + MSEFallVerticalSpeed, + MSEGuidByte3, + MSETransportGuidByte5, + MSETransportGuidByte7, + MSETransportSeat, + MSETransportGuidByte3, + MSETransportGuidByte6, + MSETransportPositionZ, + MSETransportGuidByte1, + MSETransportPositionY, + MSETransportPositionX, + MSETransportGuidByte2, + MSETransportGuidByte0, + MSETransportOrientation, + MSETransportTime, + MSETransportGuidByte4, + MSEPitch, + MSEPositionZ, + MSETimestamp, + MSEPositionX, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte1, + MSEPositionY, + MSEGuidByte0, + MSEGuidByte5, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetWalkSpeed[] = +{ + MSEHasGuidByte0, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte3, + MSEExtraElement, + MSEGuidByte6, + MSEGuidByte2, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetRunSpeed[] = +{ + MSEHasGuidByte4, + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte6, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte4, + MSEExtraElement, + MSEGuidByte2, + MSEGuidByte1, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetRunBackSpeed[] = +{ + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEHasGuidByte6, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasGuidByte7, + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEGuidByte1, + MSEExtraElement, + MSEGuidByte2, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte5, + MSEGuidByte7, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetSwimSpeed[] = +{ + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte4, + MSEExtraElement, + MSEGuidByte7, + MSEGuidByte3, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetSwimBackSpeed[] = +{ + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte6, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte6, + MSEExtraElement, + MSEGuidByte4, + MSEGuidByte2, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetTurnRate[] = +{ + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasGuidByte7, + MSEHasGuidByte0, + MSEExtraElement, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte0, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetFlightSpeed[] = +{ + MSEHasGuidByte7, + MSEHasGuidByte4, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte6, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte6, + MSEExtraElement, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetFlightBackSpeed[] = +{ + MSEHasGuidByte2, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEGuidByte5, + MSEExtraElement, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte7, + MSEGuidByte4, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetPitchRate[] = +{ + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte2, + MSEExtraElement, + MSEGuidByte4, + MSEEnd, +}; + +MovementStatusElements const MoveSetWalkSpeed[] = +{ + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte5, + MSEExtraElement, + MSEGuidByte2, + MSECounter, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte3, + MSEEnd, +}; + +MovementStatusElements const MoveSetRunSpeed[] = +{ + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasGuidByte4, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte4, + MSECounter, + MSEExtraElement, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte2, + MSEEnd, +}; + +MovementStatusElements const MoveSetRunBackSpeed[] = +{ + MSEHasGuidByte0, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasGuidByte7, + MSEGuidByte5, + MSECounter, + MSEExtraElement, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte6, + MSEEnd, +}; + +MovementStatusElements const MoveSetSwimSpeed[] = +{ + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasGuidByte3, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEGuidByte0, + MSECounter, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte5, + MSEGuidByte2, + MSEExtraElement, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte4, + MSEEnd, +}; + +MovementStatusElements const MoveSetSwimBackSpeed[] = +{ + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte6, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSECounter, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte5, + MSEGuidByte1, + MSEExtraElement, + MSEGuidByte7, + MSEGuidByte2, + MSEEnd, +}; + +MovementStatusElements const MoveSetTurnRate[] = +{ + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEGuidByte5, + MSEGuidByte7, + MSEGuidByte2, + MSEExtraElement, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte0, + MSECounter, + MSEGuidByte6, + MSEGuidByte4, + MSEEnd, +}; + +MovementStatusElements const MoveSetFlightSpeed[] = +{ + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasGuidByte4, + MSEGuidByte0, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte5, + MSEExtraElement, + MSECounter, + MSEGuidByte2, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte4, + MSEEnd, +}; + +MovementStatusElements const MoveSetFlightBackSpeed[] = +{ + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEHasGuidByte6, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasGuidByte3, + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEGuidByte3, + MSECounter, + MSEGuidByte6, + MSEExtraElement, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte7, + MSEEnd, +}; + +MovementStatusElements const MoveSetPitchRate[] = +{ + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEExtraElement, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte0, + MSECounter, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte5, + MSEEnd, +}; + +MovementStatusElements const MoveSetCollisionHeight[] = +{ + MSEZeroBit, + MSEZeroBit, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte5, + MSECounter, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte7, + MSEExtraElement, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetWalkMode[] = +{ + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEGuidByte4, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte6, + MSEGuidByte5, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte3, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetRunMode[] = +{ + MSEHasGuidByte5, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte1, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte5, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte3, + MSEEnd, +}; + +MovementStatusElements const SplineMoveGravityDisable[] = +{ + MSEHasGuidByte7, + MSEHasGuidByte3, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasGuidByte6, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte6, + MSEGuidByte2, + MSEGuidByte5, + MSEGuidByte0, + MSEEnd, +}; + +MovementStatusElements const SplineMoveGravityEnable[] = +{ + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte5, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetHover[] = +{ + MSEHasGuidByte3, + MSEHasGuidByte7, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEHasGuidByte5, + MSEGuidByte2, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte6, + MSEEnd, +}; + +MovementStatusElements const SplineMoveUnsetHover[] = +{ + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEHasGuidByte4, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte6, + MSEGuidByte1, + MSEEnd, +}; + +MovementStatusElements const SplineMoveStartSwim[] = +{ + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEGuidByte3, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte0, + MSEEnd, +}; + +MovementStatusElements const SplineMoveStopSwim[] = +{ + MSEHasGuidByte4, + MSEHasGuidByte1, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasGuidByte6, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte4, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetFlying[] = +{ + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte3, + MSEGuidByte2, + MSEEnd, +}; + +MovementStatusElements const SplineMoveUnsetFlying[] = +{ + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEGuidByte7, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte1, + MSEGuidByte6, + MSEGuidByte0, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetWaterWalk[] = +{ + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte7, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEGuidByte0, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte2, + MSEGuidByte5, + MSEGuidByte1, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetLandWalk[] = +{ + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEGuidByte5, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte6, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetFeatherFall[] = +{ + MSEHasGuidByte3, + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEGuidByte1, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte6, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte3, + MSEEnd, +}; + +MovementStatusElements const SplineMoveSetNormalFall[] = +{ + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEGuidByte7, + MSEGuidByte6, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte3, + MSEGuidByte1, + MSEEnd, +}; + +MovementStatusElements const SplineMoveRoot[] = +{ + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte7, + MSEHasGuidByte2, + MSEHasGuidByte0, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte5, + MSEGuidByte0, + MSEGuidByte6, + MSEGuidByte4, + MSEEnd, +}; + +MovementStatusElements const SplineMoveUnroot[] = +{ + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte5, + MSEHasGuidByte3, + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasGuidByte4, + MSEGuidByte6, + MSEGuidByte3, + MSEGuidByte1, + MSEGuidByte5, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte4, + MSEEnd, +}; + +MovementStatusElements const MoveSetCanFly[] = +{ + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEGuidByte6, + MSEGuidByte3, + MSECounter, + MSEGuidByte2, + MSEGuidByte1, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte0, + MSEGuidByte5, + MSEEnd, +}; + +MovementStatusElements const MoveUnsetCanFly[] = +{ + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEHasGuidByte3, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEGuidByte4, + MSEGuidByte6, + MSECounter, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte5, + MSEGuidByte7, + MSEEnd, +}; + +MovementStatusElements const MoveSetHover[] = +{ + MSEHasGuidByte1, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte0, + MSEGuidByte7, + MSECounter, + MSEEnd, +}; + +MovementStatusElements const MoveUnsetHover[] = +{ + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasGuidByte5, + MSEHasGuidByte0, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte0, + MSECounter, + MSEEnd, +}; + +MovementStatusElements const MoveWaterWalk[] = +{ + MSEHasGuidByte4, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEGuidByte0, + MSEGuidByte5, + MSEGuidByte2, + MSECounter, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte6, + MSEEnd, +}; + +MovementStatusElements const MoveLandWalk[] = +{ + MSEHasGuidByte5, + MSEHasGuidByte1, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte4, + MSEHasGuidByte0, + MSEHasGuidByte7, + MSEGuidByte6, + MSEGuidByte1, + MSEGuidByte7, + MSEGuidByte5, + MSEGuidByte4, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte2, + MSECounter, + MSEEnd, +}; + +MovementStatusElements const MoveFeatherFall[] = +{ + MSEHasGuidByte3, + MSEHasGuidByte1, + MSEHasGuidByte7, + MSEHasGuidByte0, + MSEHasGuidByte4, + MSEHasGuidByte2, + MSEHasGuidByte5, + MSEHasGuidByte6, + MSEGuidByte5, + MSEGuidByte7, + MSEGuidByte2, + MSECounter, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte1, + MSEGuidByte6, + MSEEnd, +}; + +MovementStatusElements const MoveNormalFall[] = +{ + MSECounter, + MSEHasGuidByte3, + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte5, + MSEHasGuidByte7, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEHasGuidByte2, + MSEGuidByte2, + MSEGuidByte7, + MSEGuidByte1, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte0, + MSEGuidByte3, + MSEGuidByte6, + MSEEnd, +}; + +MovementStatusElements const MoveRoot[] = +{ + MSEHasGuidByte2, + MSEHasGuidByte7, + MSEHasGuidByte6, + MSEHasGuidByte0, + MSEHasGuidByte5, + MSEHasGuidByte4, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEGuidByte1, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte5, + MSECounter, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte6, + MSEEnd, +}; + +MovementStatusElements const MoveUnroot[] = +{ + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte3, + MSEHasGuidByte7, + MSEHasGuidByte5, + MSEHasGuidByte2, + MSEHasGuidByte4, + MSEHasGuidByte6, + MSEGuidByte3, + MSEGuidByte6, + MSEGuidByte1, + MSECounter, + MSEGuidByte2, + MSEGuidByte0, + MSEGuidByte7, + MSEGuidByte4, + MSEGuidByte5, + MSEEnd, +}; + +MovementStatusElements const ChangeSeatsOnControlledVehicle[] = +{ + MSEPositionY, + MSEPositionX, + MSEPositionZ, + MSEExtraElement, + MSEHasMovementFlags, + MSEHasTransportData, + MSEHasGuidByte2, + MSEHasGuidByte6, + MSEHasGuidByte4, + MSEExtraElement, + MSEExtraElement, + MSEHasOrientation, + MSEZeroBit, + MSEExtraElement, + MSEHasGuidByte7, + MSEExtraElement, + MSEHasTimestamp, + MSEHasSplineElevation, + MSEHasGuidByte5, + MSEExtraElement, + MSEHasMovementFlags2, + MSEHasPitch, + MSEExtraElement, + MSEHasGuidByte0, + MSEExtraElement, + MSEHasFallData, + MSEHasGuidByte1, + MSEHasSpline, + MSEMovementFlags, + MSEExtraElement, + MSEHasGuidByte3, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte5, + MSEHasTransportTime3, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte2, + MSEHasTransportTime2, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte6, + MSEMovementFlags2, + MSEHasFallDirection, + MSEExtraElement, + MSEGuidByte7, + MSEGuidByte5, + MSEExtraElement, + MSEExtraElement, + MSEGuidByte6, + MSEExtraElement, + MSEExtraElement, + MSEGuidByte3, + MSEExtraElement, + MSEGuidByte0, + MSEExtraElement, + MSEGuidByte4, + MSEGuidByte1, + MSEExtraElement, + MSEGuidByte2, + MSEPitch, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSEFallTime, + MSEFallVerticalSpeed, + MSETransportGuidByte2, + MSETransportTime2, + MSETransportTime3, + MSETransportGuidByte0, + MSETransportTime, + MSETransportSeat, + MSETransportPositionX, + MSETransportOrientation, + MSETransportGuidByte7, + MSETransportGuidByte4, + MSETransportGuidByte3, + MSETransportGuidByte5, + MSETransportPositionZ, + MSETransportGuidByte1, + MSETransportGuidByte6, + MSETransportPositionY, + MSESplineElevation, + MSEOrientation, + MSETimestamp, + MSEEnd, +}; + +MovementStatusElements const CastSpellEmbeddedMovement[] = +{ + MSEPositionZ, + MSEPositionY, + MSEPositionX, + MSEHasFallData, + MSEHasTimestamp, + MSEHasOrientation, + MSEZeroBit, + MSEHasSpline, + MSEHasGuidByte6, + MSEHasGuidByte4, + MSEHasMovementFlags2, + MSEHasGuidByte3, + MSEHasGuidByte5, + MSEHasSplineElevation, + MSEHasPitch, + MSEHasGuidByte7, + MSEHasTransportData, + MSEHasGuidByte2, + MSEHasMovementFlags, + MSEHasGuidByte1, + MSEHasGuidByte0, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte5, + MSEHasTransportTime2, + MSEHasTransportGuidByte7, + MSEHasTransportGuidByte4, + MSEHasTransportTime3, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte3, + MSEMovementFlags2, + MSEMovementFlags, + MSEHasFallDirection, + MSEGuidByte1, + MSEGuidByte4, + MSEGuidByte7, + MSEGuidByte3, + MSEGuidByte0, + MSEGuidByte2, + MSEGuidByte5, + MSEGuidByte6, + MSETransportSeat, + MSETransportOrientation, + MSETransportTime, + MSETransportGuidByte6, + MSETransportGuidByte5, + MSETransportTime3, + MSETransportPositionX, + MSETransportGuidByte4, + MSETransportPositionZ, + MSETransportGuidByte2, + MSETransportGuidByte0, + MSETransportTime2, + MSETransportGuidByte1, + MSETransportGuidByte3, + MSETransportPositionY, + MSETransportGuidByte7, + MSEOrientation, + MSESplineElevation, + MSEFallTime, + MSEFallHorizontalSpeed, + MSEFallSinAngle, + MSEFallCosAngle, + MSEFallVerticalSpeed, + MSETimestamp, + MSEPitch, + MSEEnd, +}; + +void Movement::ExtraMovementStatusElement::ReadNextElement(ByteBuffer& packet) +{ + MovementStatusElements const element = _elements[_index++]; + + switch (element) + { + case MSEHasGuidByte0: + case MSEHasGuidByte1: + case MSEHasGuidByte2: + case MSEHasGuidByte3: + case MSEHasGuidByte4: + case MSEHasGuidByte5: + case MSEHasGuidByte6: + case MSEHasGuidByte7: + Data.guid[element - MSEHasGuidByte0] = packet.ReadBit(); + break; + case MSEGuidByte0: + case MSEGuidByte1: + case MSEGuidByte2: + case MSEGuidByte3: + case MSEGuidByte4: + case MSEGuidByte5: + case MSEGuidByte6: + case MSEGuidByte7: + packet.ReadByteSeq(Data.guid[element - MSEGuidByte0]); + break; + case MSEExtraFloat: + packet >> Data.floatData; + break; + case MSEExtraInt8: + packet >> Data.byteData; + break; + default: + ASSERT(PrintInvalidSequenceElement(element, __FUNCTION__)); + break; + } +} + +void Movement::ExtraMovementStatusElement::WriteNextElement(ByteBuffer& packet) +{ + MovementStatusElements const element = _elements[_index++]; + + switch (element) + { + case MSEHasGuidByte0: + case MSEHasGuidByte1: + case MSEHasGuidByte2: + case MSEHasGuidByte3: + case MSEHasGuidByte4: + case MSEHasGuidByte5: + case MSEHasGuidByte6: + case MSEHasGuidByte7: + packet.WriteBit(Data.guid[element - MSEHasGuidByte0]); + break; + case MSEGuidByte0: + case MSEGuidByte1: + case MSEGuidByte2: + case MSEGuidByte3: + case MSEGuidByte4: + case MSEGuidByte5: + case MSEGuidByte6: + case MSEGuidByte7: + packet.WriteByteSeq(Data.guid[element - MSEGuidByte0]); + break; + case MSEExtraFloat: + packet << Data.floatData; + break; + case MSEExtraInt8: + packet << Data.byteData; + break; + default: + ASSERT(PrintInvalidSequenceElement(element, __FUNCTION__)); + break; + } +} + +bool Movement::PrintInvalidSequenceElement(MovementStatusElements const element, char const* function) +{ + TC_LOG_ERROR("entities.unit", "Incorrect sequence element %d detected at %s", element, function); + return false; +} + +Movement::PacketSender::PacketSender(Unit* unit, Opcodes serverControl, Opcodes playerControl, Opcodes broadcast /*= SMSG_PLAYER_MOVE*/, ExtraMovementStatusElement* extras /*= NULL*/) + : _extraElements(extras), _unit(unit) +{ + if (unit->GetTypeId() == TYPEID_PLAYER && unit->ToPlayer()->m_mover->GetTypeId() == TYPEID_PLAYER) + { + _selfOpcode = playerControl; + _broadcast = broadcast; + } + else + { + _selfOpcode = NULL_OPCODE; + _broadcast = serverControl; + } +} + +void Movement::PacketSender::Send() const +{ + bool isPlayerMovement = false; + if (Player* player = _unit->ToPlayer()) + { + isPlayerMovement = player->m_mover->GetTypeId() == TYPEID_PLAYER; + if (isPlayerMovement && _selfOpcode != NULL_OPCODE) + { + WorldPacket data(_selfOpcode); + _unit->WriteMovementInfo(data, _extraElements); + player->SendDirectMessage(&data); + } + } + + if (_broadcast != NULL_OPCODE) + { + ///! Need to reset current extra element index before writing another packet + if (_extraElements) + _extraElements->ResetIndex(); + + WorldPacket data(_broadcast); + _unit->WriteMovementInfo(data, _extraElements); + _unit->SendMessageToSet(&data, !isPlayerMovement); + } +} + +MovementStatusElements const* GetMovementStatusElementsSequence(Opcodes opcode) +{ + switch (opcode) + { + case MSG_MOVE_FALL_LAND: + return MovementFallLand; + case MSG_MOVE_HEARTBEAT: + return MovementHeartBeat; + case MSG_MOVE_JUMP: + return MovementJump; + case MSG_MOVE_SET_FACING: + return MovementSetFacing; + case MSG_MOVE_SET_PITCH: + return MovementSetPitch; + case MSG_MOVE_START_ASCEND: + return MovementStartAscend; + case MSG_MOVE_START_BACKWARD: + return MovementStartBackward; + case MSG_MOVE_START_DESCEND: + return MovementStartDescend; + case MSG_MOVE_START_FORWARD: + return MovementStartForward; + case MSG_MOVE_START_PITCH_DOWN: + return MovementStartPitchDown; + case MSG_MOVE_START_PITCH_UP: + return MovementStartPitchUp; + case MSG_MOVE_START_STRAFE_LEFT: + return MovementStartStrafeLeft; + case MSG_MOVE_START_STRAFE_RIGHT: + return MovementStartStrafeRight; + case MSG_MOVE_START_SWIM: + return MovementStartSwim; + case MSG_MOVE_START_TURN_LEFT: + return MovementStartTurnLeft; + case MSG_MOVE_START_TURN_RIGHT: + return MovementStartTurnRight; + case MSG_MOVE_STOP: + return MovementStop; + case MSG_MOVE_STOP_ASCEND: + return MovementStopAscend; + case MSG_MOVE_STOP_PITCH: + return MovementStopPitch; + case MSG_MOVE_STOP_STRAFE: + return MovementStopStrafe; + case MSG_MOVE_STOP_SWIM: + return MovementStopSwim; + case MSG_MOVE_STOP_TURN: + return MovementStopTurn; + case SMSG_PLAYER_MOVE: + return PlayerMove; + case CMSG_MOVE_CHNG_TRANSPORT: + return MoveChngTransport; + case CMSG_MOVE_SPLINE_DONE: + return MoveSplineDone; + case CMSG_MOVE_NOT_ACTIVE_MOVER: + return MoveNotActiveMover; + case CMSG_DISMISS_CONTROLLED_VEHICLE: + return DismissControlledVehicle; + case SMSG_MOVE_UPDATE_TELEPORT: + return MoveUpdateTeleport; + case CMSG_FORCE_MOVE_ROOT_ACK: + return ForceMoveRootAck; + case CMSG_FORCE_MOVE_UNROOT_ACK: + return ForceMoveUnrootAck; + case CMSG_MOVE_FALL_RESET: + return MovementFallReset; + case CMSG_MOVE_FEATHER_FALL_ACK: + return MovementFeatherFallAck; + case CMSG_MOVE_FORCE_FLIGHT_SPEED_CHANGE_ACK: + return MovementForceFlightSpeedChangeAck; + case CMSG_MOVE_FORCE_RUN_BACK_SPEED_CHANGE_ACK: + return MovementForceRunBackSpeedChangeAck; + case CMSG_MOVE_FORCE_RUN_SPEED_CHANGE_ACK: + return MovementForceRunSpeedChangeAck; + case CMSG_MOVE_FORCE_SWIM_SPEED_CHANGE_ACK: + return MovementForceSwimSpeedChangeAck; + case CMSG_MOVE_FORCE_WALK_SPEED_CHANGE_ACK: + return MovementForceWalkSpeedChangeAck; + case CMSG_MOVE_GRAVITY_DISABLE_ACK: + return MovementGravityDisableAck; + case CMSG_MOVE_GRAVITY_ENABLE_ACK: + return MovementGravityEnableAck; + case CMSG_MOVE_HOVER_ACK: + return MovementHoverAck; + case CMSG_MOVE_KNOCK_BACK_ACK: + return MovementKnockBackAck; + case CMSG_MOVE_SET_CAN_FLY: + return MovementSetCanFly; + case CMSG_MOVE_SET_CAN_FLY_ACK: + return MovementSetCanFlyAck; + case CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK: + return MovementSetCanTransitionBetweenSwimAndFlyAck; + case SMSG_MOVE_SET_COLLISION_HEIGHT: + return MoveSetCollisionHeight; + case CMSG_MOVE_SET_COLLISION_HEIGHT_ACK: + return MovementSetCollisionHeightAck; + case SMSG_MOVE_UPDATE_COLLISION_HEIGHT: + return MovementUpdateCollisionHeight; + case CMSG_MOVE_WATER_WALK_ACK: + return MovementWaterWalkAck; + case MSG_MOVE_SET_RUN_MODE: + return MovementSetRunMode; + case MSG_MOVE_SET_WALK_MODE: + return MovementSetWalkMode; + case SMSG_MOVE_UPDATE_FLIGHT_SPEED: + return MovementUpdateFlightSpeed; + case SMSG_MOVE_UPDATE_RUN_SPEED: + return MovementUpdateRunSpeed; + case SMSG_MOVE_UPDATE_KNOCK_BACK: + return MovementUpdateKnockBack; + case SMSG_MOVE_UPDATE_RUN_BACK_SPEED: + return MovementUpdateRunBackSpeed; + case SMSG_MOVE_UPDATE_SWIM_SPEED: + return MovementUpdateSwimSpeed; + case SMSG_MOVE_UPDATE_WALK_SPEED: + return MovementUpdateWalkSpeed; + case SMSG_SPLINE_MOVE_SET_WALK_SPEED: + return SplineMoveSetWalkSpeed; + case SMSG_SPLINE_MOVE_SET_RUN_SPEED: + return SplineMoveSetRunSpeed; + case SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED: + return SplineMoveSetRunBackSpeed; + case SMSG_SPLINE_MOVE_SET_SWIM_SPEED: + return SplineMoveSetSwimSpeed; + case SMSG_SPLINE_MOVE_SET_SWIM_BACK_SPEED: + return SplineMoveSetSwimBackSpeed; + case SMSG_SPLINE_MOVE_SET_TURN_RATE: + return SplineMoveSetTurnRate; + case SMSG_SPLINE_MOVE_SET_FLIGHT_SPEED: + return SplineMoveSetFlightSpeed; + case SMSG_SPLINE_MOVE_SET_FLIGHT_BACK_SPEED: + return SplineMoveSetFlightBackSpeed; + case SMSG_SPLINE_MOVE_SET_PITCH_RATE: + return SplineMoveSetPitchRate; + case SMSG_MOVE_SET_WALK_SPEED: + return MoveSetWalkSpeed; + case SMSG_MOVE_SET_RUN_SPEED: + return MoveSetRunSpeed; + case SMSG_MOVE_SET_RUN_BACK_SPEED: + return MoveSetRunBackSpeed; + case SMSG_MOVE_SET_SWIM_SPEED: + return MoveSetSwimSpeed; + case SMSG_MOVE_SET_SWIM_BACK_SPEED: + return MoveSetSwimBackSpeed; + case SMSG_MOVE_SET_TURN_RATE: + return MoveSetTurnRate; + case SMSG_MOVE_SET_FLIGHT_SPEED: + return MoveSetFlightSpeed; + case SMSG_MOVE_SET_FLIGHT_BACK_SPEED: + return MoveSetFlightBackSpeed; + case SMSG_MOVE_SET_PITCH_RATE: + return MoveSetPitchRate; + case SMSG_SPLINE_MOVE_SET_WALK_MODE: + return SplineMoveSetWalkMode; + case SMSG_SPLINE_MOVE_SET_RUN_MODE: + return SplineMoveSetRunMode; + case SMSG_SPLINE_MOVE_GRAVITY_DISABLE: + return SplineMoveGravityDisable; + case SMSG_SPLINE_MOVE_GRAVITY_ENABLE: + return SplineMoveGravityEnable; + case SMSG_SPLINE_MOVE_SET_HOVER: + return SplineMoveSetHover; + case SMSG_SPLINE_MOVE_UNSET_HOVER: + return SplineMoveUnsetHover; + case SMSG_SPLINE_MOVE_START_SWIM: + return SplineMoveStartSwim; + case SMSG_SPLINE_MOVE_STOP_SWIM: + return SplineMoveStopSwim; + case SMSG_SPLINE_MOVE_SET_FLYING: + return SplineMoveSetFlying; + case SMSG_SPLINE_MOVE_UNSET_FLYING: + return SplineMoveUnsetFlying; + case SMSG_SPLINE_MOVE_SET_WATER_WALK: + return SplineMoveSetWaterWalk; + case SMSG_SPLINE_MOVE_SET_LAND_WALK: + return SplineMoveSetLandWalk; + case SMSG_SPLINE_MOVE_SET_FEATHER_FALL: + return SplineMoveSetFeatherFall; + case SMSG_SPLINE_MOVE_SET_NORMAL_FALL: + return SplineMoveSetNormalFall; + case SMSG_SPLINE_MOVE_ROOT: + return SplineMoveRoot; + case SMSG_SPLINE_MOVE_UNROOT: + return SplineMoveUnroot; + case SMSG_MOVE_SET_CAN_FLY: + return MoveSetCanFly; + case SMSG_MOVE_UNSET_CAN_FLY: + return MoveUnsetCanFly; + case SMSG_MOVE_SET_HOVER: + return MoveSetHover; + case SMSG_MOVE_UNSET_HOVER: + return MoveUnsetHover; + case SMSG_MOVE_WATER_WALK: + return MoveWaterWalk; + case SMSG_MOVE_LAND_WALK: + return MoveLandWalk; + case SMSG_MOVE_FEATHER_FALL: + return MoveFeatherFall; + case SMSG_MOVE_NORMAL_FALL: + return MoveNormalFall; + case SMSG_MOVE_ROOT: + return MoveRoot; + case SMSG_MOVE_UNROOT: + return MoveUnroot; + case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: + return ChangeSeatsOnControlledVehicle; + case CMSG_CAST_SPELL: + case CMSG_PET_CAST_SPELL: + case CMSG_USE_ITEM: + return CastSpellEmbeddedMovement; + default: + break; + } + + return NULL; +} diff --git a/src/server/game/Movement/MovementStructures.h b/src/server/game/Movement/MovementStructures.h new file mode 100644 index 00000000000..278eaa877fa --- /dev/null +++ b/src/server/game/Movement/MovementStructures.h @@ -0,0 +1,158 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _MOVEMENT_STRUCTURES_H +#define _MOVEMENT_STRUCTURES_H + +#include "Opcodes.h" +#include "Object.h" + +class ByteBuffer; +class Unit; + +enum MovementStatusElements +{ + MSEHasGuidByte0, + MSEHasGuidByte1, + MSEHasGuidByte2, + MSEHasGuidByte3, + MSEHasGuidByte4, + MSEHasGuidByte5, + MSEHasGuidByte6, + MSEHasGuidByte7, + MSEHasMovementFlags, + MSEHasMovementFlags2, + MSEHasTimestamp, + MSEHasOrientation, + MSEHasTransportData, + MSEHasTransportGuidByte0, + MSEHasTransportGuidByte1, + MSEHasTransportGuidByte2, + MSEHasTransportGuidByte3, + MSEHasTransportGuidByte4, + MSEHasTransportGuidByte5, + MSEHasTransportGuidByte6, + MSEHasTransportGuidByte7, + MSEHasTransportTime2, + MSEHasTransportTime3, + MSEHasPitch, + MSEHasFallData, + MSEHasFallDirection, + MSEHasSplineElevation, + MSEHasSpline, + + MSEGuidByte0, + MSEGuidByte1, + MSEGuidByte2, + MSEGuidByte3, + MSEGuidByte4, + MSEGuidByte5, + MSEGuidByte6, + MSEGuidByte7, + MSEMovementFlags, + MSEMovementFlags2, + MSETimestamp, + MSEPositionX, + MSEPositionY, + MSEPositionZ, + MSEOrientation, + MSETransportGuidByte0, + MSETransportGuidByte1, + MSETransportGuidByte2, + MSETransportGuidByte3, + MSETransportGuidByte4, + MSETransportGuidByte5, + MSETransportGuidByte6, + MSETransportGuidByte7, + MSETransportPositionX, + MSETransportPositionY, + MSETransportPositionZ, + MSETransportOrientation, + MSETransportSeat, + MSETransportTime, + MSETransportTime2, + MSETransportTime3, + MSEPitch, + MSEFallTime, + MSEFallVerticalSpeed, + MSEFallCosAngle, + MSEFallSinAngle, + MSEFallHorizontalSpeed, + MSESplineElevation, + + MSECounter, + + // Special + MSEZeroBit, // writes bit value 1 or skips read bit + MSEOneBit, // writes bit value 0 or skips read bit + MSEEnd, // marks end of parsing + MSEExtraElement, // Used to signalize reading into ExtraMovementStatusElement, element sequence inside it is declared as separate array + // Allowed internal elements are: GUID markers (not transport), MSEExtraFloat, MSEExtraInt8 + MSEExtraFloat, + MSEExtraInt8, +}; + +namespace Movement +{ + class PacketSender; + + class ExtraMovementStatusElement + { + friend class PacketSender; + + public: + ExtraMovementStatusElement(MovementStatusElements const* elements) : _elements(elements), _index(0) { } + + void ReadNextElement(ByteBuffer& packet); + void WriteNextElement(ByteBuffer& packet); + + struct + { + ObjectGuid guid; + float floatData; + int8 byteData; + } Data; + + protected: + void ResetIndex() { _index = 0; } + + private: + MovementStatusElements const* _elements; + uint32 _index; + }; + + class PacketSender + { + public: + PacketSender(Unit* unit, Opcodes serverControl, Opcodes playerControl, Opcodes broadcast = SMSG_PLAYER_MOVE, ExtraMovementStatusElement* extras = NULL); + + void Send() const; + + private: + ExtraMovementStatusElement* _extraElements; + Unit* _unit; + Opcodes _selfOpcode; + Opcodes _broadcast; + }; + + bool PrintInvalidSequenceElement(MovementStatusElements element, char const* function); +} + +MovementStatusElements const* GetMovementStatusElementsSequence(Opcodes opcode); + +#endif diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index cbf88b68028..6acee7f7a9c 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -1,4 +1,5 @@ /* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify @@ -75,6 +76,7 @@ bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool fo // make sure navMesh works - we can run on map w/o mmap // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?) if (!_navMesh || !_navMeshQuery || _sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) || + (_sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING) || !HaveTile(start) || !HaveTile(dest)) { BuildShortcut(); diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp index 7291c6849c5..6e3d7680637 100644 --- a/src/server/game/Movement/Spline/MoveSpline.cpp +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -52,7 +52,7 @@ Location MoveSpline::ComputePosition() const } else { - if (!splineflags.hasFlag(MoveSplineFlag::OrientationFixed | MoveSplineFlag::Falling)) + if (!splineflags.hasFlag(MoveSplineFlag::OrientationFixed | MoveSplineFlag::Falling | MoveSplineFlag::Unknown0)) { Vector3 hermite; spline.evaluate_derivative(point_Idx, u, hermite); @@ -216,7 +216,7 @@ bool MoveSplineInitArgs::Validate(Unit* unit) const // each vertex offset packed into 11 bytes bool MoveSplineInitArgs::_checkPathBounds() const { - if (!(flags & MoveSplineFlag::Mask_CatmullRom) && path.size() > 2) + if (!(flags & MoveSplineFlag::Catmullrom) && path.size() > 2) { enum{ MAX_OFFSET = (1 << 11) / 2 diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h index 62fe808b6f5..f9151c53fc2 100644 --- a/src/server/game/Movement/Spline/MoveSplineFlag.h +++ b/src/server/game/Movement/Spline/MoveSplineFlag.h @@ -36,42 +36,45 @@ namespace Movement enum eFlags { None = 0x00000000, - // x00-xFF(first byte) used as animation Ids storage in pair with Animation flag - Done = 0x00000100, - Falling = 0x00000200, // Affects elevation computation, can't be combined with Parabolic flag - No_Spline = 0x00000400, - Parabolic = 0x00000800, // Affects elevation computation, can't be combined with Falling flag - Walkmode = 0x00001000, - Flying = 0x00002000, // Smooth movement(Catmullrom interpolation mode), flying animation - OrientationFixed = 0x00004000, // Model orientation fixed - Final_Point = 0x00008000, - Final_Target = 0x00010000, - Final_Angle = 0x00020000, - Catmullrom = 0x00040000, // Used Catmullrom interpolation mode - Cyclic = 0x00080000, // Movement by cycled spline - Enter_Cycle = 0x00100000, // Everytimes appears with cyclic flag in monster move packet, erases first spline vertex after first cycle done - Animation = 0x00200000, // Plays animation after some time passed - Frozen = 0x00400000, // Will never arrive - TransportEnter = 0x00800000, - TransportExit = 0x01000000, - Unknown7 = 0x02000000, - Unknown8 = 0x04000000, - OrientationInversed = 0x08000000, - Unknown10 = 0x10000000, - Unknown11 = 0x20000000, - Unknown12 = 0x40000000, - Unknown13 = 0x80000000, + // x00-x07 used as animation Ids storage in pair with Animation flag + Unknown0 = 0x00000008, // NOT VERIFIED + FallingSlow = 0x00000010, + Done = 0x00000020, + Falling = 0x00000040, // Affects elevation computation, can't be combined with Parabolic flag + No_Spline = 0x00000080, + Unknown2 = 0x00000100, // NOT VERIFIED + Flying = 0x00000200, // Smooth movement(Catmullrom interpolation mode), flying animation + OrientationFixed = 0x00000400, // Model orientation fixed + Catmullrom = 0x00000800, // Used Catmullrom interpolation mode + Cyclic = 0x00001000, // Movement by cycled spline + Enter_Cycle = 0x00002000, // Everytimes appears with cyclic flag in monster move packet, erases first spline vertex after first cycle done + Frozen = 0x00004000, // Will never arrive + TransportEnter = 0x00008000, + TransportExit = 0x00010000, + Unknown3 = 0x00020000, // NOT VERIFIED + Unknown4 = 0x00040000, // NOT VERIFIED + OrientationInversed = 0x00080000, + SmoothGroundPath = 0x00100000, + Walkmode = 0x00200000, + UncompressedPath = 0x00400000, + Unknown6 = 0x00800000, // NOT VERIFIED + Animation = 0x01000000, // Plays animation after some time passed + Parabolic = 0x02000000, // Affects elevation computation, can't be combined with Falling flag + Final_Point = 0x04000000, + Final_Target = 0x08000000, + Final_Angle = 0x10000000, + Unknown7 = 0x20000000, // NOT VERIFIED + Unknown8 = 0x40000000, // NOT VERIFIED + Unknown9 = 0x80000000, // NOT VERIFIED // Masks Mask_Final_Facing = Final_Point | Final_Target | Final_Angle, // animation ids stored here, see AnimType enum, used with Animation flag - Mask_Animations = 0xFF, + Mask_Animations = 0x7, // flags that shouldn't be appended into SMSG_MONSTER_MOVE\SMSG_MONSTER_MOVE_TRANSPORT packet, should be more probably Mask_No_Monster_Move = Mask_Final_Facing | Mask_Animations | Done, - // CatmullRom interpolation mode used - Mask_CatmullRom = Flying | Catmullrom, // Unused, not suported flags - Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown7|Unknown8|Unknown10|Unknown11|Unknown12|Unknown13 + Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown0|Unknown2|Unknown3|Unknown4|Unknown6|Unknown7|Unknown8|Unknown9 }; inline uint32& raw() { return (uint32&)*this; } @@ -83,7 +86,7 @@ namespace Movement // Constant interface - bool isSmooth() const { return (raw() & Mask_CatmullRom) != 0; } + bool isSmooth() const { return (raw() & Catmullrom) != 0; } bool isLinear() const { return !isSmooth(); } bool isFacing() const { return (raw() & Mask_Final_Facing) != 0; } @@ -99,42 +102,47 @@ namespace Movement void operator &= (uint32 f) { raw() &= f; } void operator |= (uint32 f) { raw() |= f; } - void EnableAnimation(uint8 anim) { raw() = (raw() & ~(Mask_Animations | Falling | Parabolic)) | Animation | anim; } - void EnableParabolic() { raw() = (raw() & ~(Mask_Animations | Falling | Animation)) | Parabolic; } - void EnableFalling() { raw() = (raw() & ~(Mask_Animations | Parabolic | Flying | Animation)) | Falling; } - void EnableFlying() { raw() = (raw() & ~(Falling | Catmullrom)) | Flying; } - void EnableCatmullRom() { raw() = (raw() & ~Flying) | Catmullrom; } + void EnableAnimation(uint8 anim) { raw() = (raw() & ~(Mask_Animations | Falling | Parabolic | FallingSlow)) | Animation | (anim & Mask_Animations); } + void EnableParabolic() { raw() = (raw() & ~(Mask_Animations | Falling | Animation | FallingSlow)) | Parabolic; } + void EnableFlying() { raw() = (raw() & ~(Falling)) | Flying; } + void EnableFalling() { raw() = (raw() & ~(Mask_Animations | Parabolic | Animation | Flying)) | Falling; } + void EnableCatmullRom() { raw() = (raw() & ~SmoothGroundPath) | Catmullrom; } void EnableFacingPoint() { raw() = (raw() & ~Mask_Final_Facing) | Final_Point; } void EnableFacingAngle() { raw() = (raw() & ~Mask_Final_Facing) | Final_Angle; } void EnableFacingTarget() { raw() = (raw() & ~Mask_Final_Facing) | Final_Target; } void EnableTransportEnter() { raw() = (raw() & ~TransportExit) | TransportEnter; } void EnableTransportExit() { raw() = (raw() & ~TransportEnter) | TransportExit; } - uint8 animId : 8; + uint8 animId : 3; + bool unknown0 : 1; + bool fallingSlow : 1; bool done : 1; bool falling : 1; bool no_spline : 1; - bool parabolic : 1; - bool walkmode : 1; + bool unknown2 : 1; bool flying : 1; bool orientationFixed : 1; - bool final_point : 1; - bool final_target : 1; - bool final_angle : 1; bool catmullrom : 1; bool cyclic : 1; bool enter_cycle : 1; - bool animation : 1; bool frozen : 1; bool transportEnter : 1; bool transportExit : 1; + bool unknown3 : 1; + bool unknown4 : 1; + bool orientationInversed : 1; + bool smoothGroundPath : 1; + bool walkmode : 1; + bool uncompressedPath : 1; + bool unknown6 : 1; + bool animation : 1; + bool parabolic : 1; + bool final_point : 1; + bool final_target : 1; + bool final_angle : 1; bool unknown7 : 1; bool unknown8 : 1; - bool orientationInversed : 1; - bool unknown10 : 1; - bool unknown11 : 1; - bool unknown12 : 1; - bool unknown13 : 1; + bool unknown9 : 1; }; #if defined( __GNUC__ ) #pragma pack() diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp index 87d8e4a0c34..e1a15fa52b5 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.cpp +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -60,11 +60,10 @@ namespace Movement { MoveSpline& move_spline = *unit->movespline; - // Elevators also use MOVEMENTFLAG_ONTRANSPORT but we do not keep track of their position changes (movementInfo.transport.guid is 0 in that case) - bool transport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); + bool transport = unit->GetTransGUID() != 0; Location real_position; // there is a big chance that current position is unknown if current state is not finalized, need compute it - // this also allows CalculatePath spline position and update map position in much greater intervals + // this also allows calculate spline position and update map position in much greater intervals // Don't compute for transport movement if the unit is in a motion between two transports if (!move_spline.Finalized() && move_spline.onTransport == transport) real_position = move_spline.ComputePosition(); @@ -86,13 +85,13 @@ namespace Movement if (args.path.empty()) return 0; - // corrent first vertex + // correct first vertex args.path[0] = real_position; args.initialOrientation = real_position.orientation; - move_spline.onTransport = transport; + move_spline.onTransport = (unit->GetTransGUID() != 0); uint32 moveFlags = unit->m_movementInfo.GetMovementFlags(); - moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD); + moveFlags |= MOVEMENTFLAG_FORWARD; if (moveFlags & MOVEMENTFLAG_ROOT) moveFlags &= ~MOVEMENTFLAG_MASK_MOVING; @@ -118,7 +117,7 @@ namespace Movement WorldPacket data(SMSG_MONSTER_MOVE, 64); data.append(unit->GetPackGUID()); - if (transport) + if (unit->GetTransGUID()) { data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); data.appendPackGUID(unit->GetTransGUID()); @@ -139,7 +138,7 @@ namespace Movement if (move_spline.Finalized()) return; - bool transport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); + bool transport = unit->GetTransGUID() != 0; Location loc; if (move_spline.onTransport == transport) loc = move_spline.ComputePosition(); @@ -158,7 +157,7 @@ namespace Movement } args.flags = MoveSplineFlag::Done; - unit->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE_ENABLED); + unit->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FORWARD); move_spline.onTransport = transport; move_spline.Initialize(args); @@ -179,10 +178,11 @@ namespace Movement { args.splineId = splineIdGen.NewId(); // Elevators also use MOVEMENTFLAG_ONTRANSPORT but we do not keep track of their position changes - args.TransformForTransport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); + args.TransformForTransport = unit->GetTransGUID() != 0; // mix existing state into new args.flags.walkmode = unit->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING); - args.flags.flying = unit->m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY)); + args.flags.flying = unit->m_movementInfo.HasMovementFlag(MovementFlags(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY)); + args.flags.smoothGroundPath = true; // enabled by default, CatmullRom mode or client config "pathSmoothing" will disable this } void MoveSplineInit::SetFacing(const Unit* target) @@ -224,6 +224,12 @@ namespace Movement args.path[1] = transform(dest); } + void MoveSplineInit::SetFall() + { + args.flags.EnableFalling(); + args.flags.fallingSlow = unit->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW); + } + Vector3 TransportPathTransform::operator()(Vector3 input) { if (_transformForTransport) diff --git a/src/server/game/Movement/Spline/MoveSplineInit.h b/src/server/game/Movement/Spline/MoveSplineInit.h index a94c84d92f3..c968f660f58 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.h +++ b/src/server/game/Movement/Spline/MoveSplineInit.h @@ -102,27 +102,39 @@ namespace Movement * if not enabled linear spline mode will be choosen. Disabled by default */ void SetSmooth(); - /* Enables CatmullRom spline interpolation mode, enables flying animation. Disabled by default + + /* Waypoints in packets will be sent without compression + */ + void SetUncompressed(); + + /* Enables flying animation. Disabled by default */ void SetFly(); + /* Enables walk mode. Disabled by default */ void SetWalk(bool enable); + /* Makes movement cyclic. Disabled by default */ void SetCyclic(); + /* Enables falling mode. Disabled by default */ void SetFall(); + /* Enters transport. Disabled by default */ void SetTransportEnter(); + /* Exits transport. Disabled by default */ void SetTransportExit(); + /* Inverses unit model orientation. Disabled by default */ void SetOrientationInversed(); + /* Fixes unit's model rotation. Disabled by default */ void SetOrientationFixed(bool enable); @@ -148,8 +160,8 @@ namespace Movement inline void MoveSplineInit::SetFly() { args.flags.EnableFlying(); } inline void MoveSplineInit::SetWalk(bool enable) { args.flags.walkmode = enable; } inline void MoveSplineInit::SetSmooth() { args.flags.EnableCatmullRom(); } + inline void MoveSplineInit::SetUncompressed() { args.flags.uncompressedPath = true; } inline void MoveSplineInit::SetCyclic() { args.flags.cyclic = true; } - inline void MoveSplineInit::SetFall() { args.flags.EnableFalling(); } inline void MoveSplineInit::SetVelocity(float vel) { args.velocity = vel; args.HasVelocity = true; } inline void MoveSplineInit::SetOrientationInversed() { args.flags.orientationInversed = true;} inline void MoveSplineInit::SetTransportEnter() { args.flags.EnableTransportEnter(); } diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp index 51932877666..0793e51b164 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -19,7 +19,8 @@ #include "MovementPacketBuilder.h" #include "MoveSpline.h" -#include "ByteBuffer.h" +#include "WorldPacket.h" +#include "Object.h" namespace Movement { @@ -42,7 +43,7 @@ namespace Movement MonsterMoveFacingAngle = 4 }; - void PacketBuilder::WriteCommonMonsterMovePart(const MoveSpline& move_spline, ByteBuffer& data) + void PacketBuilder::WriteCommonMonsterMovePart(const MoveSpline& move_spline, WorldPacket& data) { MoveSplineFlag splineflags = move_spline.splineflags; @@ -96,10 +97,10 @@ namespace Movement data << uint8(MonsterMoveStop); } - void WriteLinearPath(const Spline<int32>& spline, ByteBuffer& data) + void WriteLinearPath(Spline<int32> const& spline, ByteBuffer& data) { uint32 last_idx = spline.getPointCount() - 3; - const Vector3 * real_path = &spline.getPoint(1); + Vector3 const* real_path = &spline.getPoint(1); data << last_idx; data << real_path[last_idx]; // destination @@ -116,14 +117,14 @@ namespace Movement } } - void WriteCatmullRomPath(const Spline<int32>& spline, ByteBuffer& data) + void WriteUncompressedPath(Spline<int32> const& spline, ByteBuffer& data) { uint32 count = spline.getPointCount() - 3; data << count; data.append<Vector3>(&spline.getPoint(2), count); } - void WriteCatmullRomCyclicPath(const Spline<int32>& spline, ByteBuffer& data) + void WriteUncompressedCyclicPath(Spline<int32> const& spline, ByteBuffer& data) { uint32 count = spline.getPointCount() - 3; data << uint32(count + 1); @@ -131,61 +132,117 @@ namespace Movement data.append<Vector3>(&spline.getPoint(1), count); } - void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, ByteBuffer& data) + void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, WorldPacket& data) { WriteCommonMonsterMovePart(move_spline, data); - const Spline<int32>& spline = move_spline.spline; + Spline<int32> const& spline = move_spline.spline; MoveSplineFlag splineflags = move_spline.splineflags; - if (splineflags & MoveSplineFlag::Mask_CatmullRom) + if (splineflags & MoveSplineFlag::UncompressedPath) { - if (splineflags.cyclic) - WriteCatmullRomCyclicPath(spline, data); + if (!splineflags.cyclic) + WriteUncompressedPath(spline, data); else - WriteCatmullRomPath(spline, data); + WriteUncompressedCyclicPath(spline, data); } else WriteLinearPath(spline, data); } - void PacketBuilder::WriteCreate(const MoveSpline& move_spline, ByteBuffer& data) + void PacketBuilder::WriteCreateBits(MoveSpline const& moveSpline, ByteBuffer& data) { - //WriteClientStatus(mov, data); - //data.append<float>(&mov.m_float_values[SpeedWalk], SpeedMaxCount); - //if (mov.SplineEnabled()) + if (!data.WriteBit(!moveSpline.Finalized())) + return; + + data.WriteBits(uint8(moveSpline.spline.mode()), 2); + data.WriteBit(moveSpline.splineflags & (MoveSplineFlag::Parabolic | MoveSplineFlag::Animation)); + data.WriteBits(moveSpline.getPath().size(), 22); + switch (moveSpline.splineflags & MoveSplineFlag::Mask_Final_Facing) + { + case MoveSplineFlag::Final_Target: + { + ObjectGuid targetGuid = moveSpline.facing.target; + data.WriteBits(2, 2); + data.WriteBit(targetGuid[4]); + data.WriteBit(targetGuid[3]); + data.WriteBit(targetGuid[7]); + data.WriteBit(targetGuid[2]); + data.WriteBit(targetGuid[6]); + data.WriteBit(targetGuid[1]); + data.WriteBit(targetGuid[0]); + data.WriteBit(targetGuid[5]); + break; + } + case MoveSplineFlag::Final_Angle: + data.WriteBits(0, 2); + break; + case MoveSplineFlag::Final_Point: + data.WriteBits(1, 2); + break; + default: + data.WriteBits(3, 2); + break; + } + + data.WriteBit((moveSpline.splineflags & MoveSplineFlag::Parabolic) && moveSpline.effect_start_time < moveSpline.Duration()); + data.WriteBits(moveSpline.splineflags.raw(), 25); + } + + void PacketBuilder::WriteCreateData(MoveSpline const& moveSpline, ByteBuffer& data) + { + if (!moveSpline.Finalized()) { - MoveSplineFlag const& splineFlags = move_spline.splineflags; + MoveSplineFlag const& splineFlags = moveSpline.splineflags; - data << splineFlags.raw(); + if ((splineFlags & MoveSplineFlag::Parabolic) && moveSpline.effect_start_time < moveSpline.Duration()) + data << moveSpline.vertical_acceleration; // added in 3.1 + + data << moveSpline.timePassed(); if (splineFlags.final_angle) - { - data << move_spline.facing.angle; - } + data << moveSpline.facing.angle; else if (splineFlags.final_target) { - data << move_spline.facing.target; + ObjectGuid facingGuid = moveSpline.facing.target; + data.WriteByteSeq(facingGuid[5]); + data.WriteByteSeq(facingGuid[3]); + data.WriteByteSeq(facingGuid[7]); + data.WriteByteSeq(facingGuid[1]); + data.WriteByteSeq(facingGuid[6]); + data.WriteByteSeq(facingGuid[4]); + data.WriteByteSeq(facingGuid[2]); + data.WriteByteSeq(facingGuid[0]); } - else if (splineFlags.final_point) + + uint32 nodes = moveSpline.getPath().size(); + for (uint32 i = 0; i < nodes; ++i) { - data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z; + data << float(moveSpline.getPath()[i].z); + data << float(moveSpline.getPath()[i].x); + data << float(moveSpline.getPath()[i].y); } - data << move_spline.timePassed(); - data << move_spline.Duration(); - data << move_spline.GetId(); + if (splineFlags.final_point) + data << moveSpline.facing.f.x << moveSpline.facing.f.z << moveSpline.facing.f.y; - data << float(1.f); // splineInfo.duration_mod; added in 3.1 data << float(1.f); // splineInfo.duration_mod_next; added in 3.1 + data << moveSpline.Duration(); + if (splineFlags & (MoveSplineFlag::Parabolic | MoveSplineFlag::Animation)) + data << moveSpline.effect_start_time; // added in 3.1 - data << move_spline.vertical_acceleration; // added in 3.1 - data << move_spline.effect_start_time; // added in 3.1 + data << float(1.f); // splineInfo.duration_mod; added in 3.1 + } - uint32 nodes = move_spline.getPath().size(); - data << nodes; - data.append<Vector3>(&move_spline.getPath()[0], nodes); - data << uint8(move_spline.spline.mode()); // added in 3.1 - data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination()); + if (!moveSpline.isCyclic()) + { + Vector3 dest = moveSpline.FinalDestination(); + data << float(dest.z); + data << float(dest.x); + data << float(dest.y); } + else + data << Vector3::zero(); + + data << moveSpline.GetId(); } } diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.h b/src/server/game/Movement/Spline/MovementPacketBuilder.h index d1ad3d61eec..750cdc0fdbf 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.h +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.h @@ -20,27 +20,25 @@ #ifndef TRINITYSERVER_PACKET_BUILDER_H #define TRINITYSERVER_PACKET_BUILDER_H -#include "Define.h" +#include "Define.h" // for uint32 +#include "G3D/Vector3.h" +using G3D::Vector3; class ByteBuffer; -namespace G3D -{ - class Vector3; -} +class WorldPacket; namespace Movement { - using G3D::Vector3; - class MoveSpline; class PacketBuilder { - static void WriteCommonMonsterMovePart(const MoveSpline& mov, ByteBuffer& data); + static void WriteCommonMonsterMovePart(const MoveSpline& mov, WorldPacket& data); public: - static void WriteMonsterMove(const MoveSpline& mov, ByteBuffer& data); + static void WriteMonsterMove(const MoveSpline& mov, WorldPacket& data); static void WriteStopMovement(Vector3 const& loc, uint32 splineId, ByteBuffer& data); - static void WriteCreate(const MoveSpline& mov, ByteBuffer& data); + static void WriteCreateBits(MoveSpline const& moveSpline, ByteBuffer& data); + static void WriteCreateData(MoveSpline const& moveSpline, ByteBuffer& data); }; } #endif // TRINITYSERVER_PACKET_BUILDER_H diff --git a/src/server/game/Movement/Spline/MovementTypedefs.h b/src/server/game/Movement/Spline/MovementTypedefs.h index 635c43757be..134e7a45425 100644 --- a/src/server/game/Movement/Spline/MovementTypedefs.h +++ b/src/server/game/Movement/Spline/MovementTypedefs.h @@ -71,6 +71,8 @@ namespace Movement extern double gravity; extern UInt32Counter splineIdGen; + extern std::string MovementFlags_ToString(uint32 flags); + extern std::string MovementFlagsExtra_ToString(uint32 flags); } #endif // TRINITYSERVER_TYPEDEFS_H diff --git a/src/server/game/Movement/Spline/MovementUtil.cpp b/src/server/game/Movement/Spline/MovementUtil.cpp index 375859263ab..f5bdba378d1 100644 --- a/src/server/game/Movement/Spline/MovementUtil.cpp +++ b/src/server/game/Movement/Spline/MovementUtil.cpp @@ -98,82 +98,86 @@ namespace Movement STR(Pitch_Up ), // 0x00000040, STR(Pitch_Down ), // 0x00000080, - STR(Walk ), // 0x00000100, // Walking - STR(Ontransport ), // 0x00000200, - STR(Levitation ), // 0x00000400, - STR(Root ), // 0x00000800, - STR(Falling ), // 0x00001000, - STR(Fallingfar ), // 0x00002000, - STR(Pendingstop ), // 0x00004000, - STR(PendingSTRafestop ), // 0x00008000, - STR(Pendingforward ), // 0x00010000, - STR(Pendingbackward ), // 0x00020000, - STR(PendingSTRafeleft ), // 0x00040000, - STR(PendingSTRaferight ), // 0x00080000, - STR(Pendingroot ), // 0x00100000, - STR(Swimming ), // 0x00200000, // Appears With Fly Flag Also - STR(Ascending ), // 0x00400000, // Swim Up Also - STR(Descending ), // 0x00800000, // Swim Down Also - STR(Can_Fly ), // 0x01000000, // Can Fly In 3.3? - STR(Flying ), // 0x02000000, // Actual Flying Mode - STR(Spline_Elevation ), // 0x04000000, // Used For Flight Paths - STR(Spline_Enabled ), // 0x08000000, // Used For Flight Paths - STR(Waterwalking ), // 0x10000000, // Prevent Unit From Falling Through Water - STR(Safe_Fall ), // 0x20000000, // Active Rogue Safe Fall Spell (Passive) - STR(Hover ), // 0x40000000 - STR(Unknown13 ), // 0x80000000 - STR(Unk1 ), - STR(Unk2 ), - STR(Unk3 ), - STR(Fullspeedturning ), - STR(Fullspeedpitching ), - STR(Allow_Pitching ), - STR(Unk4 ), - STR(Unk5 ), - STR(Unk6 ), - STR(Unk7 ), - STR(Interp_Move ), - STR(Interp_Turning ), - STR(Interp_Pitching ), - STR(Unk8 ), - STR(Unk9 ), - STR(Unk10 ), + STR(Walking ), // 0x00000100, // Walking + STR(DisableGravity ), // 0x00000200, + STR(Root ), // 0x00000400, + STR(Falling ), // 0x00000800, + STR(FallingFar ), // 0x00001000, + STR(PendingStop ), // 0x00002000, + STR(PendingStrafeStop ), // 0x00004000, + STR(PendingForward ), // 0x00008000, + STR(PendingBackward ), // 0x00010000, + STR(PendingStrafeLeft ), // 0x00020000, + STR(PendingStrafeRight ), // 0x00040000, + STR(PendingRoot ), // 0x00080000, + STR(Swimming ), // 0x00100000, // Appears With Fly Flag Also + STR(Ascending ), // 0x00200000, // Swim Up Also + STR(Descending ), // 0x00400000, // Swim Down Also + STR(Can_Fly ), // 0x00800000, // Can Fly In 3.3? + STR(Flying ), // 0x01000000, // Actual Flying Mode + STR(Spline_Elevation ), // 0x02000000, // Used For Flight Paths + STR(Waterwalking ), // 0x04000000, // Prevent Unit From Falling Through Water + STR(Safe_Fall ), // 0x08000000, // Active Rogue Safe Fall Spell (Passive) + STR(Hover ), // 0x10000000 + STR(Local_Dirty ), // 0x20000000 + STR(None31 ), // 0x40000000 + STR(None32 ), // 0x80000000 + }; + + char const* g_MovementFlagExtra_names[] = + { + STR(NoStrafe ), + STR(NoJump ), + STR(FullSpeedTurning ), + STR(FullSpeedPitching ), + STR(Allow_Pitching ), + STR(Unk6 ), + STR(Unk7 ), + STR(Unk8 ), + STR(Unk9 ), + STR(Unk10 ), + STR(Unk11 ), + STR(Unk12 ), + STR(Unk13 ), + STR(Interpolated_Movement), + STR(Interpolated_Turning ), + STR(Interpolated_Pitching), }; char const* g_SplineFlag_names[32] = { - STR(AnimBit1 ), // 0x00000001, - STR(AnimBit2 ), // 0x00000002, - STR(AnimBit3 ), // 0x00000004, - STR(AnimBit4 ), // 0x00000008, - STR(AnimBit5 ), // 0x00000010, - STR(AnimBit6 ), // 0x00000020, - STR(AnimBit7 ), // 0x00000040, - STR(AnimBit8 ), // 0x00000080, - STR(Done ), // 0x00000100, - STR(Falling ), // 0x00000200, // Not Compartible With Trajectory Movement - STR(No_Spline ), // 0x00000400, - STR(Trajectory ), // 0x00000800, // Not Compartible With Fall Movement - STR(Walkmode ), // 0x00001000, - STR(Flying ), // 0x00002000, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation - STR(Knockback ), // 0x00004000, // Model Orientation Fixed - STR(Final_Point ), // 0x00008000, - STR(Final_Target ), // 0x00010000, - STR(Final_Angle ), // 0x00020000, - STR(Catmullrom ), // 0x00040000, // Used Catmullrom Interpolation Mode - STR(Cyclic ), // 0x00080000, // Movement By Cycled Spline - STR(Enter_Cycle ), // 0x00100000, // Everytime Appears With Cyclic Flag In Monster Move Packet - STR(Animation ), // 0x00200000, // Animationid (0...3), Uint32 Time, Not Compartible With Trajectory And Fall Movement - STR(Unknown4 ), // 0x00400000, // Disables Movement By Path - STR(Unknown5 ), // 0x00800000, - STR(Unknown6 ), // 0x01000000, - STR(Unknown7 ), // 0x02000000, - STR(Unknown8 ), // 0x04000000, - STR(OrientationInversed ), // 0x08000000, // Appears With Runmode Flag, Nodes ), // 1, Handles Orientation - STR(Unknown10 ), // 0x10000000, - STR(Unknown11 ), // 0x20000000, - STR(Unknown12 ), // 0x40000000, - STR(Unknown13 ), // 0x80000000, + STR(AnimBit1 ), // 0x00000001, + STR(AnimBit2 ), // 0x00000002, + STR(AnimBit3 ), // 0x00000004, + STR(Unknown0 ), // 0x00000008, + STR(FallingSlow ), // 0x00000010, + STR(Done ), // 0x00000020, + STR(Falling ), // 0x00000040, // Not Compartible With Trajectory Movement + STR(No_Spline ), // 0x00000080, + STR(Unknown2 ), // 0x00000100, + STR(Flying ), // 0x00000200, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation + STR(OrientationFixed ), // 0x00000400, // Model Orientation Fixed + STR(Catmullrom ), // 0x00000800, // Used Catmullrom Interpolation Mode + STR(Cyclic ), // 0x00001000, // Movement By Cycled Spline + STR(Enter_Cycle ), // 0x00002000, // Everytime Appears With Cyclic Flag In Monster Move Packet + STR(Frozen ), // 0x00004000, + STR(TransportEnter ), // 0x00008000 + STR(TransportExit ), // 0x00010000 + STR(Unknown3 ), // 0x00020000, + STR(Unknown4 ), // 0x00040000, + STR(OrientationInversed), // 0x00080000, // Appears With Runmode Flag, Nodes ), // 1, Handles Orientation + STR(SmoothGroundPath ), // 0x00100000, + STR(Walkmode ), // 0x00200000, + STR(UncompressedPath ), // 0x00400000, + STR(Unknown6 ), // 0x00800000, + STR(Animation ), // 0x01000000, // Animationid (0...3), Uint32 Time, Not Compartible With Trajectory And Fall Movement + STR(Parabolic ), // 0x02000000, // Not Compartible With Fall Movement + STR(Final_Point ), // 0x04000000, + STR(Final_Target ), // 0x08000000, + STR(Final_Angle ), // 0x10000000, + STR(Unknown7 ), // 0x20000000, + STR(Unknown8 ), // 0x40000000, + STR(Unknown9 ), // 0x80000000, }; template<class Flags, int N> @@ -192,4 +196,18 @@ namespace Movement print_flags(raw(), g_SplineFlag_names, str); return str; } + + std::string MovementFlags_ToString(uint32 flags) + { + std::string str; + print_flags(flags, g_MovementFlag_names, str); + return str; + } + + std::string MovementFlagsExtra_ToString(uint32 flags) + { + std::string str; + print_flags(flags, g_MovementFlagExtra_names, str); + return str; + } } diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.h b/src/server/game/OutdoorPvP/OutdoorPvP.h index 9a7cc92c2ed..577d70021a6 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.h +++ b/src/server/game/OutdoorPvP/OutdoorPvP.h @@ -30,11 +30,10 @@ enum OutdoorPvPTypes OUTDOOR_PVP_NA = 2, OUTDOOR_PVP_TF = 3, OUTDOOR_PVP_ZM = 4, - OUTDOOR_PVP_SI = 5, - OUTDOOR_PVP_EP = 6 + OUTDOOR_PVP_SI = 5 }; -#define MAX_OUTDOORPVP_TYPES 7 +#define MAX_OUTDOORPVP_TYPES 6 enum ObjectiveStates { diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index a26b14af4b7..7c089eee07b 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -19,20 +19,21 @@ #include "QuestDef.h" #include "Player.h" #include "World.h" +#include "ObjectMgr.h" Quest::Quest(Field* questRecord) { Id = questRecord[0].GetUInt32(); Method = questRecord[1].GetUInt8(); Level = questRecord[2].GetInt16(); - MinLevel = questRecord[3].GetUInt8(); - MaxLevel = questRecord[4].GetUInt8(); + MinLevel = uint32(questRecord[3].GetInt16()); + MaxLevel = uint32(questRecord[4].GetInt16()); ZoneOrSort = questRecord[5].GetInt16(); Type = questRecord[6].GetUInt16(); SuggestedPlayers = questRecord[7].GetUInt8(); LimitTime = questRecord[8].GetUInt32(); RequiredClasses = questRecord[9].GetUInt16(); - RequiredRaces = questRecord[10].GetUInt16(); + RequiredRaces = questRecord[10].GetUInt32(); RequiredSkillId = questRecord[11].GetUInt16(); RequiredSkillPoints = questRecord[12].GetUInt16(); RequiredFactionId1 = questRecord[13].GetUInt16(); @@ -61,91 +62,117 @@ Quest::Quest(Field* questRecord) SourceSpellid = questRecord[36].GetUInt32(); Flags = questRecord[37].GetUInt32(); SpecialFlags = questRecord[38].GetUInt8(); - RewardTitleId = questRecord[39].GetUInt8(); - RequiredPlayerKills = questRecord[40].GetUInt8(); - RewardTalents = questRecord[41].GetUInt8(); - RewardArenaPoints = questRecord[42].GetUInt16(); - + MinimapTargetMark = questRecord[39].GetUInt8(); + RewardTitleId = questRecord[40].GetUInt8(); + RequiredPlayerKills = questRecord[41].GetUInt8(); + RewardTalents = questRecord[42].GetUInt8(); + RewardArenaPoints = questRecord[43].GetUInt16(); + RewardSkillId = questRecord[44].GetUInt16(); + RewardSkillPoints = questRecord[45].GetUInt8(); + RewardReputationMask = questRecord[46].GetUInt8(); + QuestGiverPortrait = questRecord[47].GetUInt32(); + QuestTurnInPortrait = questRecord[48].GetUInt32(); for (int i = 0; i < QUEST_REWARDS_COUNT; ++i) - RewardItemId[i] = questRecord[43+i].GetUInt32(); + RewardItemId[i] = questRecord[49+i].GetUInt32(); for (int i = 0; i < QUEST_REWARDS_COUNT; ++i) - RewardItemIdCount[i] = questRecord[47+i].GetUInt16(); + RewardItemIdCount[i] = questRecord[53+i].GetUInt16(); for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) - RewardChoiceItemId[i] = questRecord[51+i].GetUInt32(); + RewardChoiceItemId[i] = questRecord[57+i].GetUInt32(); for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) - RewardChoiceItemCount[i] = questRecord[57+i].GetUInt16(); + RewardChoiceItemCount[i] = questRecord[63+i].GetUInt16(); for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - RewardFactionId[i] = questRecord[63+i].GetUInt16(); + RewardFactionId[i] = questRecord[69+i].GetUInt16(); for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - RewardFactionValueId[i] = questRecord[68+i].GetInt32(); + RewardFactionValueId[i] = questRecord[74+i].GetInt32(); for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - RewardFactionValueIdOverride[i] = questRecord[73+i].GetInt32(); - - PointMapId = questRecord[78].GetUInt16(); - PointX = questRecord[79].GetFloat(); - PointY = questRecord[80].GetFloat(); - PointOption = questRecord[81].GetUInt32(); - Title = questRecord[82].GetString(); - Objectives = questRecord[83].GetString(); - Details = questRecord[84].GetString(); - EndText = questRecord[85].GetString(); - OfferRewardText = questRecord[86].GetString(); - RequestItemsText = questRecord[87].GetString(); - CompletedText = questRecord[88].GetString(); + RewardFactionValueIdOverride[i] = questRecord[79+i].GetInt32(); + + PointMapId = questRecord[84].GetUInt16(); + PointX = questRecord[85].GetFloat(); + PointY = questRecord[86].GetFloat(); + PointOption = questRecord[87].GetUInt32(); + Title = questRecord[88].GetString(); + Objectives = questRecord[89].GetString(); + Details = questRecord[90].GetString(); + EndText = questRecord[91].GetString(); + CompletedText = questRecord[92].GetString(); + OfferRewardText = questRecord[93].GetString(); + RequestItemsText = questRecord[94].GetString(); for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - RequiredNpcOrGo[i] = questRecord[89+i].GetInt32(); + RequiredNpcOrGo[i] = questRecord[95+i].GetInt32(); for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - RequiredNpcOrGoCount[i] = questRecord[93+i].GetUInt16(); + RequiredNpcOrGoCount[i] = questRecord[99+i].GetUInt16(); for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) - RequiredSourceItemId[i] = questRecord[97+i].GetUInt32(); + RequiredSourceItemId[i] = questRecord[103+i].GetUInt32(); for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) - RequiredSourceItemCount[i] = questRecord[101+i].GetUInt16(); + RequiredSourceItemCount[i] = questRecord[107+i].GetUInt16(); for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) - RequiredItemId[i] = questRecord[105+i].GetUInt32(); + RequiredItemId[i] = questRecord[111+i].GetUInt32(); for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) - RequiredItemCount[i] = questRecord[111+i].GetUInt16(); + RequiredItemCount[i] = questRecord[117+i].GetUInt16(); - // int8 Unknown0 = questRecord[117].GetUInt8(); + RequiredSpell = questRecord[123].GetUInt32(); for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - ObjectiveText[i] = questRecord[118+i].GetString(); + ObjectiveText[i] = questRecord[124+i].GetString(); + + for (int i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) + RewardCurrencyId[i] = questRecord[128+i].GetUInt16(); + + for (int i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) + RewardCurrencyCount[i] = questRecord[132+i].GetUInt8(); + + for (int i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i) + RequiredCurrencyId[i] = questRecord[136+i].GetUInt16(); + + for (int i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i) + RequiredCurrencyCount[i] = questRecord[140+i].GetUInt8(); + + QuestGiverTextWindow = questRecord[144].GetString(); + QuestGiverTargetName = questRecord[145].GetString(); + QuestTurnTextWindow = questRecord[146].GetString(); + QuestTurnTargetName = questRecord[147].GetString(); + SoundAccept = questRecord[148].GetUInt16(); + SoundTurnIn = questRecord[149].GetUInt16(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - DetailsEmote[i] = questRecord[122+i].GetUInt16(); + DetailsEmote[i] = questRecord[150+i].GetUInt16(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - DetailsEmoteDelay[i] = questRecord[126+i].GetUInt32(); + DetailsEmoteDelay[i] = questRecord[154+i].GetUInt32(); - EmoteOnIncomplete = questRecord[130].GetUInt16(); - EmoteOnComplete = questRecord[131].GetUInt16(); + EmoteOnIncomplete = questRecord[158].GetUInt16(); + EmoteOnComplete = questRecord[159].GetUInt16(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - OfferRewardEmote[i] = questRecord[132+i].GetInt16(); + OfferRewardEmote[i] = questRecord[160+i].GetInt16(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - OfferRewardEmoteDelay[i] = questRecord[136+i].GetInt32(); + OfferRewardEmoteDelay[i] = questRecord[164+i].GetInt32(); - //int32 VerifiedBuild = questRecord[140].GetInt32(); + //int32 VerifiedBuild = questRecord[168].GetInt32(); if (SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) Flags |= QUEST_FLAGS_AUTO_ACCEPT; _reqItemsCount = 0; - _reqCreatureOrGOcount = 0; + _reqNpcOrGoCount = 0; _rewItemsCount = 0; _rewChoiceItemsCount = 0; + _rewCurrencyCount = 0; + _reqCurrencyCount = 0; for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) if (RequiredItemId[i]) @@ -153,7 +180,7 @@ Quest::Quest(Field* questRecord) for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) if (RequiredNpcOrGo[i]) - ++_reqCreatureOrGOcount; + ++_reqNpcOrGoCount; for (int i = 0; i < QUEST_REWARDS_COUNT; ++i) if (RewardItemId[i]) @@ -162,6 +189,14 @@ Quest::Quest(Field* questRecord) for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) if (RewardChoiceItemId[i]) ++_rewChoiceItemsCount; + + for (int i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) + if (RewardCurrencyId[i]) + ++_rewCurrencyCount; + + for (int i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i) + if (RequiredCurrencyId[i]) + ++_reqCurrencyCount; } uint32 Quest::XPValue(Player* player) const @@ -203,6 +238,79 @@ int32 Quest::GetRewOrReqMoney() const return int32(RewardOrRequiredMoney * sWorld->getRate(RATE_DROP_MONEY)); } +void Quest::BuildExtraQuestInfo(WorldPacket& data, Player* player) const +{ + data << uint32(GetRewChoiceItemsCount()); + for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) + data << uint32(RewardChoiceItemId[i]); + for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) + data << uint32(RewardChoiceItemCount[i]); + for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) + { + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(RewardChoiceItemId[i])) + data << uint32(itemTemplate->DisplayInfoID); + else + data << uint32(0); + } + + data << uint32(GetReqItemsCount()); + for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) + data << uint32(RewardItemId[i]); + for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) + data << uint32(RewardItemIdCount[i]); + for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) + { + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(RewardItemId[i])) + data << uint32(itemTemplate->DisplayInfoID); + else + data << uint32(0); + } + + data << uint32(GetRewOrReqMoney()); + data << uint32(XPValue(player) * sWorld->getRate(RATE_XP_QUEST)); + + data << uint32(GetCharTitleId()); + data << uint32(0); // unk + data << float(0.0f); // unk + data << uint32(GetBonusTalents()); + data << uint32(0); // unk + data << uint32(GetRewardReputationMask()); + + /* Pre cata struct, some of these unks might be the missing values in cata: + // rewarded honor points. Multiply with 10 to satisfy client + data << 10 * Trinity::Honor::hk_honor_at_level(_session->GetPlayer()->getLevel(), quest->GetRewHonorMultiplier()); + data << float(0); // unk, honor multiplier? + data << uint32(0x08); // unused by client? + data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast == 0) + data << int32(quest->GetRewSpellCast()); // casted spell + data << uint32(0); // unknown + data << uint32(quest->GetBonusTalents()); // bonus talents + data << uint32(quest->GetRewArenaPoints()); // arena points + data << uint32(0); + */ + + for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids + data << uint32(RewardFactionId[i]); + + for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid in QuestFactionReward.dbc (zero based)? + data << int32(RewardFactionValueId[i]); + + for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward reputation override? + data << uint32(RewardFactionValueIdOverride[i]); + + data << uint32(GetRewSpell()); + data << uint32(GetRewSpellCast()); + + for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) + data << uint32(RewardCurrencyId[i]); + + for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) + data << uint32(RewardCurrencyCount[i]); + + data << uint32(GetRewardSkillId()); + data << uint32(GetRewardSkillPoints()); +} + uint32 Quest::GetRewMoneyMaxLevel() const { if (HasFlag(QUEST_FLAGS_NO_MONEY_FROM_XP)) @@ -218,7 +326,7 @@ bool Quest::IsAutoAccept() const bool Quest::IsAutoComplete() const { - return !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) && (Method == 0 || HasFlag(QUEST_FLAGS_AUTOCOMPLETE)); + return !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) && Method == 0; } bool Quest::IsRaidQuest(Difficulty difficulty) const @@ -253,7 +361,7 @@ uint32 Quest::CalculateHonorGain(uint8 level) const uint32 honor = 0; - if (GetRewHonorAddition() > 0 || GetRewHonorMultiplier() > 0.0f) + /*if (GetRewHonorAddition() > 0 || GetRewHonorMultiplier() > 0.0f) { // values stored from 0.. for 1... TeamContributionPointsEntry const* tc = sTeamContributionPointsStore.LookupEntry(level); @@ -262,7 +370,7 @@ uint32 Quest::CalculateHonorGain(uint8 level) const honor = uint32(tc->value * GetRewHonorMultiplier() * 0.1f); honor += GetRewHonorAddition(); - } + }*/ return honor; } diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 350ef104ed4..79b7a4b428e 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -22,6 +22,7 @@ #include "Define.h" #include "DatabaseEnv.h" #include "SharedDefines.h" +#include "WorldPacket.h" #include "DBCEnums.h" #include <string> @@ -42,6 +43,8 @@ class ObjectMgr; #define QUEST_REPUTATIONS_COUNT 5 #define QUEST_EMOTE_COUNT 4 #define QUEST_PVP_KILL_SLOT 0 +#define QUEST_REWARD_CURRENCY_COUNT 4 +#define QUEST_REQUIRED_CURRENCY_COUNT 4 enum QuestFailedReason { @@ -108,25 +111,25 @@ enum QuestStatus enum QuestGiverStatus { - DIALOG_STATUS_NONE = 0, - DIALOG_STATUS_UNAVAILABLE = 1, - DIALOG_STATUS_LOW_LEVEL_AVAILABLE = 2, - DIALOG_STATUS_LOW_LEVEL_REWARD_REP = 3, - DIALOG_STATUS_LOW_LEVEL_AVAILABLE_REP = 4, - DIALOG_STATUS_INCOMPLETE = 5, - DIALOG_STATUS_REWARD_REP = 6, - DIALOG_STATUS_AVAILABLE_REP = 7, - DIALOG_STATUS_AVAILABLE = 8, - DIALOG_STATUS_REWARD2 = 9, // no yellow dot on minimap - DIALOG_STATUS_REWARD = 10, // yellow dot on minimap + DIALOG_STATUS_NONE = 0x000, + DIALOG_STATUS_UNK = 0x001, + DIALOG_STATUS_UNAVAILABLE = 0x002, + DIALOG_STATUS_LOW_LEVEL_AVAILABLE = 0x004, + DIALOG_STATUS_LOW_LEVEL_REWARD_REP = 0x008, + DIALOG_STATUS_LOW_LEVEL_AVAILABLE_REP = 0x010, + DIALOG_STATUS_INCOMPLETE = 0x020, + DIALOG_STATUS_REWARD_REP = 0x040, + DIALOG_STATUS_AVAILABLE_REP = 0x080, + DIALOG_STATUS_AVAILABLE = 0x100, + DIALOG_STATUS_REWARD2 = 0x200, // no yellow dot on minimap + DIALOG_STATUS_REWARD = 0x400, // yellow dot on minimap // Custom value meaning that script call did not return any valid quest status - DIALOG_STATUS_SCRIPTED_NO_STATUS = 0x1000, + DIALOG_STATUS_SCRIPTED_NO_STATUS = 0x1000 }; enum QuestFlags { - // Flags used at server and sent to client QUEST_FLAGS_NONE = 0x00000000, QUEST_FLAGS_STAY_ALIVE = 0x00000001, // Not used currently QUEST_FLAGS_PARTY_ACCEPT = 0x00000002, // Not used currently. If player in party, all players that can accept this quest will receive confirmation box to accept quest CMSG_QUEST_CONFIRM_ACCEPT/SMSG_QUEST_CONFIRM_ACCEPT @@ -144,11 +147,15 @@ enum QuestFlags QUEST_FLAGS_FLAGS_PVP = 0x00002000, // Having this quest in log forces PvP flag QUEST_FLAGS_UNAVAILABLE = 0x00004000, // Used on quests that are not generically available QUEST_FLAGS_WEEKLY = 0x00008000, - QUEST_FLAGS_AUTOCOMPLETE = 0x00010000, // auto complete + QUEST_FLAGS_AUTOCOMPLETE = 0x00010000, // Quests with this flag player submit automatically by special button in player gui QUEST_FLAGS_DISPLAY_ITEM_IN_TRACKER = 0x00020000, // Displays usable item in quest tracker QUEST_FLAGS_OBJ_TEXT = 0x00040000, // use Objective text as Complete text QUEST_FLAGS_AUTO_ACCEPT = 0x00080000, // The client recognizes this flag as auto-accept. However, NONE of the current quests (3.3.5a) have this flag. Maybe blizz used to use it, or will use it in the future. - + QUEST_FLAGS_UNK1 = 0x00100000, // + QUEST_FLAGS_AUTO_TAKE = 0x00200000, // Automatically suggestion of accepting quest. Not from npc. + //QUEST_FLAGS_UNK2 = 0x00400000, + //QUEST_FLAGS_UNK3 = 0x00800000, // Found in quest 14069 + //QUEST_FLAGS_UNK4 = 0x01000000, // ... 4.x added flags up to 0x80000000 - all unknown for now }; @@ -185,6 +192,11 @@ struct QuestLocale StringVector EndText; StringVector CompletedText; std::vector< StringVector > ObjectiveText; + // new on 4.x + StringVector QuestGiverTextWindow; + StringVector QuestGiverTargetName; + StringVector QuestTurnTextWindow; + StringVector QuestTurnTargetName; }; // This Quest class provides a convenient way to access a few pretotaled (cached) quest details, @@ -244,6 +256,10 @@ class Quest std::string const& GetRequestItemsText() const { return RequestItemsText; } std::string const& GetEndText() const { return EndText; } std::string const& GetCompletedText() const { return CompletedText; } + std::string const& GetQuestGiverTextWindow() const { return QuestGiverTextWindow; } + std::string const& GetQuestGiverTargetName() const { return QuestGiverTargetName; } + std::string const& GetQuestTurnTextWindow() const { return QuestTurnTextWindow; } + std::string const& GetQuestTurnTargetName() const { return QuestTurnTargetName; } int32 GetRewOrReqMoney() const; uint32 GetRewHonorAddition() const { return RewardHonor; } float GetRewHonorMultiplier() const { return RewardHonorMultiplier; } @@ -256,12 +272,22 @@ class Quest float GetPointX() const { return PointX; } float GetPointY() const { return PointY; } uint32 GetPointOpt() const { return PointOption; } + uint32 GetRequiredSpell() const { return RequiredSpell; } + uint32 GetSoundAccept() const { return SoundAccept; } + uint32 GetSoundTurnIn() const { return SoundTurnIn; } uint32 GetIncompleteEmote() const { return EmoteOnIncomplete; } uint32 GetCompleteEmote() const { return EmoteOnComplete; } bool IsRepeatable() const { return SpecialFlags & QUEST_SPECIAL_FLAGS_REPEATABLE; } bool IsAutoAccept() const; bool IsAutoComplete() const; uint32 GetFlags() const { return Flags; } + uint32 GetSpecialFlags() const { return SpecialFlags; } + uint32 GetMinimapTargetMark() const { return MinimapTargetMark; } + uint32 GetRewardSkillId() const { return RewardSkillId; } + uint32 GetRewardSkillPoints() const { return RewardSkillPoints; } + uint32 GetRewardReputationMask() const { return RewardReputationMask; } + uint32 GetQuestGiverPortrait() const { return QuestGiverPortrait; } + uint32 GetQuestTurnInPortrait() const { return QuestTurnInPortrait; } bool IsDaily() const { return (Flags & QUEST_FLAGS_DAILY) != 0; } bool IsWeekly() const { return (Flags & QUEST_FLAGS_WEEKLY) != 0; } bool IsMonthly() const { return (SpecialFlags & QUEST_SPECIAL_FLAGS_MONTHLY) != 0; } @@ -291,11 +317,20 @@ class Quest uint32 DetailsEmoteDelay[QUEST_EMOTE_COUNT]; uint32 OfferRewardEmote[QUEST_EMOTE_COUNT]; uint32 OfferRewardEmoteDelay[QUEST_EMOTE_COUNT]; + // 4.x + uint32 RewardCurrencyId[QUEST_REWARD_CURRENCY_COUNT]; + uint32 RewardCurrencyCount[QUEST_REWARD_CURRENCY_COUNT]; + uint32 RequiredCurrencyId[QUEST_REQUIRED_CURRENCY_COUNT]; + uint32 RequiredCurrencyCount[QUEST_REQUIRED_CURRENCY_COUNT]; uint32 GetReqItemsCount() const { return _reqItemsCount; } - uint32 GetReqCreatureOrGOcount() const { return _reqCreatureOrGOcount; } + uint32 GetReqCreatureOrGOcount() const { return _reqNpcOrGoCount; } uint32 GetRewChoiceItemsCount() const { return _rewChoiceItemsCount; } uint32 GetRewItemsCount() const { return _rewItemsCount; } + uint32 GetRewCurrencyCount() const { return _rewCurrencyCount; } + uint32 GetReqCurrencyCount() const { return _reqCurrencyCount; } + + void BuildExtraQuestInfo(WorldPacket& data, Player* player) const; typedef std::vector<int32> PrevQuests; PrevQuests prevQuests; @@ -305,9 +340,11 @@ class Quest // cached data private: uint32 _reqItemsCount; - uint32 _reqCreatureOrGOcount; + uint32 _reqNpcOrGoCount; uint32 _rewChoiceItemsCount; uint32 _rewItemsCount; + uint32 _rewCurrencyCount; + uint32 _reqCurrencyCount; // table data protected: @@ -366,6 +403,20 @@ class Quest uint32 PointOption; uint32 EmoteOnIncomplete; uint32 EmoteOnComplete; + // new in 4.x + uint32 MinimapTargetMark; + uint32 RewardSkillId; + uint32 RewardSkillPoints; + uint32 RewardReputationMask; + uint32 QuestGiverPortrait; + uint32 QuestTurnInPortrait; + uint32 RequiredSpell; + std::string QuestGiverTextWindow; + std::string QuestGiverTargetName; + std::string QuestTurnTextWindow; + std::string QuestTurnTargetName; + uint32 SoundAccept; + uint32 SoundTurnIn; uint32 SpecialFlags; // custom flags, not sniffed/WDB }; diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp index f19d6d754cf..b136e6893cd 100644 --- a/src/server/game/Reputation/ReputationMgr.cpp +++ b/src/server/game/Reputation/ReputationMgr.cpp @@ -24,6 +24,7 @@ #include "World.h" #include "ObjectMgr.h" #include "ScriptMgr.h" +#include "Opcodes.h" #include "WorldSession.h" const int32 ReputationMgr::PointsInRank[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000}; @@ -198,7 +199,7 @@ void ReputationMgr::SendState(FactionState const* faction) void ReputationMgr::SendInitialReputations() { - uint8 count = 128; + uint16 count = 256; WorldPacket data(SMSG_INITIALIZE_FACTIONS, 4 + count * 5); data << uint32(count); diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 862b8dffddb..c9b65c3a046 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -49,6 +49,7 @@ void AddSC_account_commandscript(); void AddSC_achievement_commandscript(); void AddSC_arena_commandscript(); void AddSC_ban_commandscript(); +void AddSC_battlenet_account_commandscript(); void AddSC_bf_commandscript(); void AddSC_cast_commandscript(); void AddSC_character_commandscript(); @@ -106,6 +107,10 @@ void AddSC_boss_balinda(); void AddSC_boss_drekthar(); void AddSC_boss_galvangar(); void AddSC_boss_vanndar(); +void AddSC_boss_alizabal(); //Baradin Hold +void AddSC_boss_occuthar(); +void AddSC_boss_pit_lord_argaloth(); +void AddSC_instance_baradin_hold(); void AddSC_blackrock_depths(); //Blackrock Depths void AddSC_boss_ambassador_flamelash(); void AddSC_boss_anubshiah(); @@ -242,24 +247,19 @@ void AddSC_boss_halazzi(); void AddSC_boss_hex_lord_malacrass(); void AddSC_boss_janalai(); void AddSC_boss_nalorakk(); -void AddSC_boss_zuljin(); +void AddSC_boss_daakara(); void AddSC_instance_zulaman(); void AddSC_zulaman(); -void AddSC_boss_jeklik(); //Zul'Gurub -void AddSC_boss_venoxis(); -void AddSC_boss_marli(); -void AddSC_boss_mandokir(); -void AddSC_boss_gahzranka(); -void AddSC_boss_thekal(); -void AddSC_boss_arlokk(); -void AddSC_boss_jindo(); -void AddSC_boss_hakkar(); -void AddSC_boss_grilek(); +void AddSC_boss_grilek(); // Zul'Gurub void AddSC_boss_hazzarah(); +void AddSC_boss_jindo_the_godbreaker(); +void AddSC_boss_kilnara(); +void AddSC_boss_mandokir(); void AddSC_boss_renataki(); +void AddSC_boss_venoxis(); void AddSC_boss_wushoolay(); +void AddSC_boss_zanzil(); void AddSC_instance_zulgurub(); - //void AddSC_alterac_mountains(); void AddSC_arathi_highlands(); void AddSC_blasted_lands(); @@ -351,12 +351,17 @@ void AddSC_instance_wailing_caverns(); void AddSC_boss_zum_rah(); //Zul'Farrak void AddSC_zulfarrak(); void AddSC_instance_zulfarrak(); +void AddSC_instance_halls_of_origination(); +void AddSC_boss_temple_guardian_anhuur(); +void AddSC_boss_earthrager_ptah(); +void AddSC_boss_anraphet(); +void AddSC_instance_firelands(); +void AddSC_boss_alysrazor(); void AddSC_ashenvale(); void AddSC_azshara(); void AddSC_azuremyst_isle(); void AddSC_bloodmyst_isle(); -void AddSC_boss_azuregos(); void AddSC_darkshore(); void AddSC_desolace(); void AddSC_durotar(); @@ -671,6 +676,9 @@ void AddSC_shattrath_city(); void AddSC_terokkar_forest(); void AddSC_zangarmarsh(); +// Maelstrom +void AddSC_kezan(); + // Events void AddSC_event_childrens_week(); @@ -685,7 +693,6 @@ void AddSC_shaman_pet_scripts(); // battlegrounds // outdoor pvp -void AddSC_outdoorpvp_ep(); void AddSC_outdoorpvp_hp(); void AddSC_outdoorpvp_na(); void AddSC_outdoorpvp_si(); @@ -710,6 +717,7 @@ void AddScripts() AddKalimdorScripts(); AddOutlandScripts(); AddNorthrendScripts(); + AddMaelstromScripts(); AddEventScripts(); AddPetScripts(); AddBattlegroundScripts(); @@ -752,6 +760,7 @@ void AddCommandScripts() AddSC_achievement_commandscript(); AddSC_arena_commandscript(); AddSC_ban_commandscript(); + AddSC_battlenet_account_commandscript(); AddSC_bf_commandscript(); AddSC_cast_commandscript(); AddSC_character_commandscript(); @@ -818,6 +827,10 @@ void AddEasternKingdomsScripts() AddSC_boss_drekthar(); AddSC_boss_galvangar(); AddSC_boss_vanndar(); + AddSC_boss_alizabal(); //Baradin Hold + AddSC_boss_occuthar(); + AddSC_boss_pit_lord_argaloth(); + AddSC_instance_baradin_hold(); AddSC_blackrock_depths(); //Blackrock Depths AddSC_boss_ambassador_flamelash(); AddSC_boss_anubshiah(); @@ -954,22 +967,18 @@ void AddEasternKingdomsScripts() AddSC_boss_hex_lord_malacrass(); AddSC_boss_janalai(); AddSC_boss_nalorakk(); - AddSC_boss_zuljin(); + AddSC_boss_daakara(); AddSC_instance_zulaman(); AddSC_zulaman(); - AddSC_boss_jeklik(); //Zul'Gurub - AddSC_boss_venoxis(); - AddSC_boss_marli(); - AddSC_boss_mandokir(); - AddSC_boss_gahzranka(); - AddSC_boss_thekal(); - AddSC_boss_arlokk(); - AddSC_boss_jindo(); - AddSC_boss_hakkar(); - AddSC_boss_grilek(); + AddSC_boss_grilek(); // Zul'Gurub AddSC_boss_hazzarah(); + AddSC_boss_jindo_the_godbreaker(); + AddSC_boss_kilnara(); + AddSC_boss_mandokir(); AddSC_boss_renataki(); + AddSC_boss_venoxis(); AddSC_boss_wushoolay(); + AddSC_boss_zanzil(); AddSC_instance_zulgurub(); //AddSC_alterac_mountains(); @@ -1072,7 +1081,6 @@ void AddKalimdorScripts() AddSC_azshara(); AddSC_azuremyst_isle(); AddSC_bloodmyst_isle(); - AddSC_boss_azuregos(); AddSC_darkshore(); AddSC_desolace(); AddSC_durotar(); @@ -1091,6 +1099,14 @@ void AddKalimdorScripts() AddSC_thunder_bluff(); AddSC_ungoro_crater(); AddSC_winterspring(); + + AddSC_instance_halls_of_origination(); + AddSC_boss_temple_guardian_anhuur(); + AddSC_boss_earthrager_ptah(); + AddSC_boss_anraphet(); + + AddSC_instance_firelands(); + AddSC_boss_alysrazor(); #endif } @@ -1395,6 +1411,14 @@ void AddNorthrendScripts() #endif } + +void AddMaelstromScripts() +{ +#ifdef SCRIPTS + AddSC_kezan(); +#endif +} + void AddEventScripts() { #ifdef SCRIPTS @@ -1417,7 +1441,6 @@ void AddPetScripts() void AddOutdoorPvPScripts() { #ifdef SCRIPTS - AddSC_outdoorpvp_ep(); AddSC_outdoorpvp_hp(); AddSC_outdoorpvp_na(); AddSC_outdoorpvp_si(); diff --git a/src/server/game/Scripting/ScriptLoader.h b/src/server/game/Scripting/ScriptLoader.h index db4c5b0cf46..a68f78997b3 100644 --- a/src/server/game/Scripting/ScriptLoader.h +++ b/src/server/game/Scripting/ScriptLoader.h @@ -27,6 +27,7 @@ void AddEasternKingdomsScripts(); void AddKalimdorScripts(); void AddOutlandScripts(); void AddNorthrendScripts(); +void AddMaelstromScripts(); void AddEventScripts(); void AddPetScripts(); void AddBattlegroundScripts(); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 0d1983ab463..6d0be13c35e 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -1187,7 +1187,7 @@ void ScriptMgr::OnPlayerTalentsReset(Player* player, bool noCost) FOREACH_SCRIPT(PlayerScript)->OnTalentsReset(player, noCost); } -void ScriptMgr::OnPlayerMoneyChanged(Player* player, int32& amount) +void ScriptMgr::OnPlayerMoneyChanged(Player* player, int64& amount) { FOREACH_SCRIPT(PlayerScript)->OnMoneyChanged(player, amount); } @@ -1359,12 +1359,12 @@ void ScriptMgr::OnGuildDisband(Guild* guild) FOREACH_SCRIPT(GuildScript)->OnDisband(guild); } -void ScriptMgr::OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint32 &amount, bool isRepair) +void ScriptMgr::OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint64 &amount, bool isRepair) { FOREACH_SCRIPT(GuildScript)->OnMemberWitdrawMoney(guild, player, amount, isRepair); } -void ScriptMgr::OnGuildMemberDepositMoney(Guild* guild, Player* player, uint32 &amount) +void ScriptMgr::OnGuildMemberDepositMoney(Guild* guild, Player* player, uint64 &amount) { FOREACH_SCRIPT(GuildScript)->OnMemberDepositMoney(guild, player, amount); } diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 0b5813a7f58..104410a1345 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -60,7 +60,6 @@ class WorldPacket; class WorldSocket; class WorldObject; -struct AchievementCriteriaData; struct AuctionEntry; struct ConditionSourceInfo; struct Condition; @@ -706,7 +705,7 @@ class PlayerScript : public UnitScript virtual void OnTalentsReset(Player* /*player*/, bool /*noCost*/) { } // Called when a player's money is modified (before the modification is done) - virtual void OnMoneyChanged(Player* /*player*/, int32& /*amount*/) { } + virtual void OnMoneyChanged(Player* /*player*/, int64& /*amount*/) { } // Called when a player gains XP (before anything is given) virtual void OnGiveXP(Player* /*player*/, uint32& /*amount*/, Unit* /*victim*/) { } @@ -826,10 +825,10 @@ class GuildScript : public ScriptObject virtual void OnDisband(Guild* /*guild*/) { } // Called when a guild member withdraws money from a guild bank. - virtual void OnMemberWitdrawMoney(Guild* /*guild*/, Player* /*player*/, uint32& /*amount*/, bool /*isRepair*/) { } + virtual void OnMemberWitdrawMoney(Guild* /*guild*/, Player* /*player*/, uint64& /*amount*/, bool /*isRepair*/) { } // Called when a guild member deposits money in a guild bank. - virtual void OnMemberDepositMoney(Guild* /*guild*/, Player* /*player*/, uint32& /*amount*/) { } + virtual void OnMemberDepositMoney(Guild* /*guild*/, Player* /*player*/, uint64& /*amount*/) { } // Called when a guild member moves an item in a guild bank. virtual void OnItemMove(Guild* /*guild*/, Player* /*player*/, Item* /*pItem*/, bool /*isSrcBank*/, uint8 /*srcContainer*/, uint8 /*srcSlotId*/, @@ -1052,7 +1051,7 @@ class ScriptMgr void OnPlayerLevelChanged(Player* player, uint8 oldLevel); void OnPlayerFreeTalentPointsChanged(Player* player, uint32 newPoints); void OnPlayerTalentsReset(Player* player, bool noCost); - void OnPlayerMoneyChanged(Player* player, int32& amount); + void OnPlayerMoneyChanged(Player* player, int64& amount); void OnGivePlayerXP(Player* player, uint32& amount, Unit* victim); void OnPlayerReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental); void OnPlayerDuelRequest(Player* target, Player* challenger); @@ -1092,8 +1091,8 @@ class ScriptMgr void OnGuildInfoChanged(Guild* guild, const std::string& newInfo); void OnGuildCreate(Guild* guild, Player* leader, const std::string& name); void OnGuildDisband(Guild* guild); - void OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint32 &amount, bool isRepair); - void OnGuildMemberDepositMoney(Guild* guild, Player* player, uint32 &amount); + void OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint64 &amount, bool isRepair); + void OnGuildMemberDepositMoney(Guild* guild, Player* player, uint64 &amount); void OnGuildItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, bool isDestBank, uint8 destContainer, uint8 destSlotId); void OnGuildEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank); diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index ea02b83f2e8..cc5e9413b7a 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -16,1325 +16,1643 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - \ingroup u2w -*/ - #include "Opcodes.h" #include "WorldSession.h" +OpcodeTable opcodeTable; + +template<bool isInValidRange, bool isNonZero> +void OpcodeTable::ValidateAndSetOpcode(uint16 /*opcode*/, char const* /*name*/, SessionStatus /*status*/, PacketProcessing /*processing*/, pOpcodeHandler /*handler*/) +{ + // if for some reason we are here, that means NUM_OPCODE_HANDLERS == 0 (or your compiler is broken) +} + +template<> +void OpcodeTable::ValidateAndSetOpcode<true, true>(uint16 opcode, char const* name, SessionStatus status, PacketProcessing processing, pOpcodeHandler handler) +{ + if (_internalTable[opcode] != NULL) + { + TC_LOG_ERROR("network", "Tried to override handler of %s with %s (opcode %u)", opcodeTable[opcode]->Name, name, opcode); + return; + } + + _internalTable[opcode] = new OpcodeHandler(name, status, processing, handler); +} + +template<> +void OpcodeTable::ValidateAndSetOpcode<false, true>(uint16 opcode, char const* /*name*/, SessionStatus /*status*/, PacketProcessing /*processing*/, pOpcodeHandler /*handler*/) +{ + TC_LOG_ERROR("network", "Tried to set handler for an invalid opcode %d", opcode); +} + +template<> +void OpcodeTable::ValidateAndSetOpcode<true, false>(uint16 /*opcode*/, char const* name, SessionStatus /*status*/, PacketProcessing /*processing*/, pOpcodeHandler /*handler*/) +{ + TC_LOG_ERROR("network", "Opcode %s got value 0", name); +} + /// Correspondence between opcodes and their names -OpcodeHandler opcodeTable[NUM_MSG_TYPES] = +void OpcodeTable::Initialize() { - /*0x000*/ { "MSG_NULL_ACTION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x001*/ { "CMSG_BOOTME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x002*/ { "CMSG_DBLOOKUP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x003*/ { "SMSG_DBLOOKUP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x004*/ { "CMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x005*/ { "SMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x006*/ { "CMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x007*/ { "SMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x008*/ { "CMSG_WORLD_TELEPORT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWorldTeleportOpcode }, - /*0x009*/ { "CMSG_TELEPORT_TO_UNIT", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x00A*/ { "CMSG_ZONE_MAP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x00B*/ { "SMSG_ZONE_MAP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x00C*/ { "CMSG_DEBUG_CHANGECELLZONE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x00D*/ { "CMSG_MOVE_CHARACTER_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x00E*/ { "SMSG_MOVE_CHARACTER_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x00F*/ { "CMSG_RECHARGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x010*/ { "CMSG_LEARN_SPELL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x011*/ { "CMSG_CREATEMONSTER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x012*/ { "CMSG_DESTROYMONSTER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x013*/ { "CMSG_CREATEITEM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x014*/ { "CMSG_CREATEGAMEOBJECT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x015*/ { "SMSG_CHECK_FOR_BOTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x016*/ { "CMSG_MAKEMONSTERATTACKGUID", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x017*/ { "CMSG_BOT_DETECTED2", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x018*/ { "CMSG_FORCEACTION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x019*/ { "CMSG_FORCEACTIONONOTHER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x01A*/ { "CMSG_FORCEACTIONSHOW", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x01B*/ { "SMSG_FORCEACTIONSHOW", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x01C*/ { "CMSG_PETGODMODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x01D*/ { "SMSG_PETGODMODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x01E*/ { "SMSG_REFER_A_FRIEND_EXPIRED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x01F*/ { "CMSG_WEATHER_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x020*/ { "CMSG_UNDRESSPLAYER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x021*/ { "CMSG_BEASTMASTER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x022*/ { "CMSG_GODMODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x023*/ { "SMSG_GODMODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x024*/ { "CMSG_CHEAT_SETMONEY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x025*/ { "CMSG_LEVEL_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x026*/ { "CMSG_PET_LEVEL_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x027*/ { "CMSG_SET_WORLDSTATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x028*/ { "CMSG_COOLDOWN_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x029*/ { "CMSG_USE_SKILL_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x02A*/ { "CMSG_FLAG_QUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x02B*/ { "CMSG_FLAG_QUEST_FINISH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x02C*/ { "CMSG_CLEAR_QUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x02D*/ { "CMSG_SEND_EVENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x02E*/ { "CMSG_DEBUG_AISTATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x02F*/ { "SMSG_DEBUG_AISTATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x030*/ { "CMSG_DISABLE_PVP_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x031*/ { "CMSG_ADVANCE_SPAWN_TIME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x032*/ { "SMSG_DESTRUCTIBLE_BUILDING_DAMAGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x033*/ { "CMSG_AUTH_SRP6_BEGIN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x034*/ { "CMSG_AUTH_SRP6_PROOF", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x035*/ { "CMSG_AUTH_SRP6_RECODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x036*/ { "CMSG_CHAR_CREATE", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharCreateOpcode }, - /*0x037*/ { "CMSG_CHAR_ENUM", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharEnumOpcode }, - /*0x038*/ { "CMSG_CHAR_DELETE", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharDeleteOpcode }, - /*0x039*/ { "SMSG_AUTH_SRP6_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x03A*/ { "SMSG_CHAR_CREATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x03B*/ { "SMSG_CHAR_ENUM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x03C*/ { "SMSG_CHAR_DELETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x03D*/ { "CMSG_PLAYER_LOGIN", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandlePlayerLoginOpcode }, - /*0x03E*/ { "SMSG_NEW_WORLD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x03F*/ { "SMSG_TRANSFER_PENDING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x040*/ { "SMSG_TRANSFER_ABORTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x041*/ { "SMSG_CHARACTER_LOGIN_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x042*/ { "SMSG_LOGIN_SETTIMESPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x043*/ { "SMSG_GAMETIME_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x044*/ { "CMSG_GAMETIME_SET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x045*/ { "SMSG_GAMETIME_SET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x046*/ { "CMSG_GAMESPEED_SET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x047*/ { "SMSG_GAMESPEED_SET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x048*/ { "CMSG_SERVERTIME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x049*/ { "SMSG_SERVERTIME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x04A*/ { "CMSG_PLAYER_LOGOUT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePlayerLogoutOpcode }, - /*0x04B*/ { "CMSG_LOGOUT_REQUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutRequestOpcode }, - /*0x04C*/ { "SMSG_LOGOUT_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x04D*/ { "SMSG_LOGOUT_COMPLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x04E*/ { "CMSG_LOGOUT_CANCEL", STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutCancelOpcode }, - /*0x04F*/ { "SMSG_LOGOUT_CANCEL_ACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x050*/ { "CMSG_NAME_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNameQueryOpcode }, - /*0x051*/ { "SMSG_NAME_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x052*/ { "CMSG_PET_NAME_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetNameQuery }, - /*0x053*/ { "SMSG_PET_NAME_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x054*/ { "CMSG_GUILD_QUERY", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildQueryOpcode }, - /*0x055*/ { "SMSG_GUILD_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x056*/ { "CMSG_ITEM_QUERY_SINGLE", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleItemQuerySingleOpcode }, - /*0x057*/ { "CMSG_ITEM_QUERY_MULTIPLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x058*/ { "SMSG_ITEM_QUERY_SINGLE_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x059*/ { "SMSG_ITEM_QUERY_MULTIPLE_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x05A*/ { "CMSG_PAGE_TEXT_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePageTextQueryOpcode }, - /*0x05B*/ { "SMSG_PAGE_TEXT_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x05C*/ { "CMSG_QUEST_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestQueryOpcode }, - /*0x05D*/ { "SMSG_QUEST_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x05E*/ { "CMSG_GAMEOBJECT_QUERY", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGameObjectQueryOpcode }, - /*0x05F*/ { "SMSG_GAMEOBJECT_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x060*/ { "CMSG_CREATURE_QUERY", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleCreatureQueryOpcode }, - /*0x061*/ { "SMSG_CREATURE_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x062*/ { "CMSG_WHO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWhoOpcode }, - /*0x063*/ { "SMSG_WHO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x064*/ { "CMSG_WHOIS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWhoisOpcode }, - /*0x065*/ { "SMSG_WHOIS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x066*/ { "CMSG_CONTACT_LIST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleContactListOpcode }, - /*0x067*/ { "SMSG_CONTACT_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x068*/ { "SMSG_FRIEND_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x069*/ { "CMSG_ADD_FRIEND", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddFriendOpcode }, - /*0x06A*/ { "CMSG_DEL_FRIEND", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDelFriendOpcode }, - /*0x06B*/ { "CMSG_SET_CONTACT_NOTES", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetContactNotesOpcode }, - /*0x06C*/ { "CMSG_ADD_IGNORE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddIgnoreOpcode }, - /*0x06D*/ { "CMSG_DEL_IGNORE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDelIgnoreOpcode }, - /*0x06E*/ { "CMSG_GROUP_INVITE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupInviteOpcode }, - /*0x06F*/ { "SMSG_GROUP_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x070*/ { "CMSG_GROUP_CANCEL", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x071*/ { "SMSG_GROUP_CANCEL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x072*/ { "CMSG_GROUP_ACCEPT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupAcceptOpcode }, - /*0x073*/ { "CMSG_GROUP_DECLINE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupDeclineOpcode }, - /*0x074*/ { "SMSG_GROUP_DECLINE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x075*/ { "CMSG_GROUP_UNINVITE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupUninviteOpcode }, - /*0x076*/ { "CMSG_GROUP_UNINVITE_GUID", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupUninviteGuidOpcode }, - /*0x077*/ { "SMSG_GROUP_UNINVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x078*/ { "CMSG_GROUP_SET_LEADER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupSetLeaderOpcode }, - /*0x079*/ { "SMSG_GROUP_SET_LEADER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x07A*/ { "CMSG_LOOT_METHOD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMethodOpcode }, - /*0x07B*/ { "CMSG_GROUP_DISBAND", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupDisbandOpcode }, - /*0x07C*/ { "SMSG_GROUP_DESTROYED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x07D*/ { "SMSG_GROUP_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x07E*/ { "SMSG_PARTY_MEMBER_STATS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x07F*/ { "SMSG_PARTY_COMMAND_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x080*/ { "UMSG_UPDATE_GROUP_MEMBERS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x081*/ { "CMSG_GUILD_CREATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildCreateOpcode }, - /*0x082*/ { "CMSG_GUILD_INVITE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildInviteOpcode }, - /*0x083*/ { "SMSG_GUILD_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x084*/ { "CMSG_GUILD_ACCEPT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildAcceptOpcode }, - /*0x085*/ { "CMSG_GUILD_DECLINE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildDeclineOpcode }, - /*0x086*/ { "SMSG_GUILD_DECLINE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x087*/ { "CMSG_GUILD_INFO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildInfoOpcode }, - /*0x088*/ { "SMSG_GUILD_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x089*/ { "CMSG_GUILD_ROSTER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildRosterOpcode }, - /*0x08A*/ { "SMSG_GUILD_ROSTER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x08B*/ { "CMSG_GUILD_PROMOTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildPromoteOpcode }, - /*0x08C*/ { "CMSG_GUILD_DEMOTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildDemoteOpcode }, - /*0x08D*/ { "CMSG_GUILD_LEAVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildLeaveOpcode }, - /*0x08E*/ { "CMSG_GUILD_REMOVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildRemoveOpcode }, - /*0x08F*/ { "CMSG_GUILD_DISBAND", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildDisbandOpcode }, - /*0x090*/ { "CMSG_GUILD_LEADER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildLeaderOpcode }, - /*0x091*/ { "CMSG_GUILD_MOTD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildMOTDOpcode }, - /*0x092*/ { "SMSG_GUILD_EVENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x093*/ { "SMSG_GUILD_COMMAND_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x094*/ { "UMSG_UPDATE_GUILD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x095*/ { "CMSG_MESSAGECHAT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode }, - /*0x096*/ { "SMSG_MESSAGECHAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x097*/ { "CMSG_JOIN_CHANNEL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleJoinChannel }, - /*0x098*/ { "CMSG_LEAVE_CHANNEL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLeaveChannel }, - /*0x099*/ { "SMSG_CHANNEL_NOTIFY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x09A*/ { "CMSG_CHANNEL_LIST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelList }, - /*0x09B*/ { "SMSG_CHANNEL_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x09C*/ { "CMSG_CHANNEL_PASSWORD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelPassword }, - /*0x09D*/ { "CMSG_CHANNEL_SET_OWNER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelSetOwner }, - /*0x09E*/ { "CMSG_CHANNEL_OWNER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelOwner }, - /*0x09F*/ { "CMSG_CHANNEL_MODERATOR", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelModerator }, - /*0x0A0*/ { "CMSG_CHANNEL_UNMODERATOR", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelUnmoderator }, - /*0x0A1*/ { "CMSG_CHANNEL_MUTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelMute }, - /*0x0A2*/ { "CMSG_CHANNEL_UNMUTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelUnmute }, - /*0x0A3*/ { "CMSG_CHANNEL_INVITE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelInvite }, - /*0x0A4*/ { "CMSG_CHANNEL_KICK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelKick }, - /*0x0A5*/ { "CMSG_CHANNEL_BAN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelBan }, - /*0x0A6*/ { "CMSG_CHANNEL_UNBAN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelUnban }, - /*0x0A7*/ { "CMSG_CHANNEL_ANNOUNCEMENTS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelAnnouncements }, - /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL }, - /*0x0A9*/ { "SMSG_UPDATE_OBJECT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0AA*/ { "SMSG_DESTROY_OBJECT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0AB*/ { "CMSG_USE_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUseItemOpcode }, - /*0x0AC*/ { "CMSG_OPEN_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleOpenItemOpcode }, - /*0x0AD*/ { "CMSG_READ_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReadItem }, - /*0x0AE*/ { "SMSG_READ_ITEM_OK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0AF*/ { "SMSG_READ_ITEM_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0B0*/ { "SMSG_ITEM_COOLDOWN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0B1*/ { "CMSG_GAMEOBJ_USE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGameObjectUseOpcode }, - /*0x0B2*/ { "CMSG_DESTROY_ITEMS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0B3*/ { "SMSG_GAMEOBJECT_CUSTOM_ANIM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0B4*/ { "CMSG_AREATRIGGER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaTriggerOpcode }, - /*0x0B5*/ { "MSG_MOVE_START_FORWARD", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0B6*/ { "MSG_MOVE_START_BACKWARD", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0B7*/ { "MSG_MOVE_STOP", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0B8*/ { "MSG_MOVE_START_STRAFE_LEFT", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0B9*/ { "MSG_MOVE_START_STRAFE_RIGHT", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0BA*/ { "MSG_MOVE_STOP_STRAFE", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0BB*/ { "MSG_MOVE_JUMP", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0BC*/ { "MSG_MOVE_START_TURN_LEFT", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0BD*/ { "MSG_MOVE_START_TURN_RIGHT", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0BE*/ { "MSG_MOVE_STOP_TURN", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0BF*/ { "MSG_MOVE_START_PITCH_UP", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0C0*/ { "MSG_MOVE_START_PITCH_DOWN", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0C1*/ { "MSG_MOVE_STOP_PITCH", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0C2*/ { "MSG_MOVE_SET_RUN_MODE", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0C3*/ { "MSG_MOVE_SET_WALK_MODE", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0C4*/ { "MSG_MOVE_TOGGLE_LOGGING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0C5*/ { "MSG_MOVE_TELEPORT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0C6*/ { "MSG_MOVE_TELEPORT_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0C7*/ { "MSG_MOVE_TELEPORT_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveTeleportAck }, - /*0x0C8*/ { "MSG_MOVE_TOGGLE_FALL_LOGGING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0C9*/ { "MSG_MOVE_FALL_LAND", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0CA*/ { "MSG_MOVE_START_SWIM", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0CB*/ { "MSG_MOVE_STOP_SWIM", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0CC*/ { "MSG_MOVE_SET_RUN_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0CD*/ { "MSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0CE*/ { "MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0CF*/ { "MSG_MOVE_SET_RUN_BACK_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D0*/ { "MSG_MOVE_SET_WALK_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D1*/ { "MSG_MOVE_SET_WALK_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D2*/ { "MSG_MOVE_SET_SWIM_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D3*/ { "MSG_MOVE_SET_SWIM_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D4*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D5*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D6*/ { "MSG_MOVE_SET_ALL_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D7*/ { "MSG_MOVE_SET_TURN_RATE_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D8*/ { "MSG_MOVE_SET_TURN_RATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0D9*/ { "MSG_MOVE_TOGGLE_COLLISION_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0DA*/ { "MSG_MOVE_SET_FACING", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0DB*/ { "MSG_MOVE_SET_PITCH", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0DC*/ { "MSG_MOVE_WORLDPORT_ACK", STATUS_TRANSFER, PROCESS_THREADUNSAFE, &WorldSession::HandleMoveWorldportAckOpcode }, - /*0x0DD*/ { "SMSG_MONSTER_MOVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0DE*/ { "SMSG_MOVE_WATER_WALK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0DF*/ { "SMSG_MOVE_LAND_WALK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0E0*/ { "CMSG_MOVE_CHARM_PORT_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0E1*/ { "CMSG_MOVE_SET_RAW_POSITION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0E2*/ { "SMSG_FORCE_RUN_SPEED_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0E3*/ { "CMSG_FORCE_RUN_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck }, - /*0x0E4*/ { "SMSG_FORCE_RUN_BACK_SPEED_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0E5*/ { "CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck }, - /*0x0E6*/ { "SMSG_FORCE_SWIM_SPEED_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0E7*/ { "CMSG_FORCE_SWIM_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck }, - /*0x0E8*/ { "SMSG_FORCE_MOVE_ROOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0E9*/ { "CMSG_FORCE_MOVE_ROOT_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveRootAck }, - /*0x0EA*/ { "SMSG_FORCE_MOVE_UNROOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0EB*/ { "CMSG_FORCE_MOVE_UNROOT_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveUnRootAck }, - /*0x0EC*/ { "MSG_MOVE_ROOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0ED*/ { "MSG_MOVE_UNROOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0EE*/ { "MSG_MOVE_HEARTBEAT", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x0EF*/ { "SMSG_MOVE_KNOCK_BACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0F0*/ { "CMSG_MOVE_KNOCK_BACK_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveKnockBackAck }, - /*0x0F1*/ { "MSG_MOVE_KNOCK_BACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0F2*/ { "SMSG_MOVE_FEATHER_FALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0F3*/ { "SMSG_MOVE_NORMAL_FALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0F4*/ { "SMSG_MOVE_SET_HOVER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0F5*/ { "SMSG_MOVE_UNSET_HOVER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0F6*/ { "CMSG_MOVE_HOVER_ACK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMoveHoverAck }, - /*0x0F7*/ { "MSG_MOVE_HOVER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0F8*/ { "CMSG_TRIGGER_CINEMATIC_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0F9*/ { "CMSG_OPENING_CINEMATIC", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x0FA*/ { "SMSG_TRIGGER_CINEMATIC", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0FB*/ { "CMSG_NEXT_CINEMATIC_CAMERA", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNextCinematicCamera }, - /*0x0FC*/ { "CMSG_COMPLETE_CINEMATIC", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCompleteCinematic }, - /*0x0FD*/ { "SMSG_TUTORIAL_FLAGS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x0FE*/ { "CMSG_TUTORIAL_FLAG", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialFlag }, - /*0x0FF*/ { "CMSG_TUTORIAL_CLEAR", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialClear }, - /*0x100*/ { "CMSG_TUTORIAL_RESET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialReset }, - /*0x101*/ { "CMSG_STANDSTATECHANGE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleStandStateChangeOpcode }, - /*0x102*/ { "CMSG_EMOTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEmoteOpcode }, - /*0x103*/ { "SMSG_EMOTE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x104*/ { "CMSG_TEXT_EMOTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTextEmoteOpcode }, - /*0x105*/ { "SMSG_TEXT_EMOTE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x106*/ { "CMSG_AUTOEQUIP_GROUND_ITEM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x107*/ { "CMSG_AUTOSTORE_GROUND_ITEM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x108*/ { "CMSG_AUTOSTORE_LOOT_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutostoreLootItemOpcode }, - /*0x109*/ { "CMSG_STORE_LOOT_IN_SLOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x10A*/ { "CMSG_AUTOEQUIP_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemOpcode }, - /*0x10B*/ { "CMSG_AUTOSTORE_BAG_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBagItemOpcode }, - /*0x10C*/ { "CMSG_SWAP_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapItem }, - /*0x10D*/ { "CMSG_SWAP_INV_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapInvItemOpcode }, - /*0x10E*/ { "CMSG_SPLIT_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSplitItemOpcode }, - /*0x10F*/ { "CMSG_AUTOEQUIP_ITEM_SLOT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemSlotOpcode }, - /*0x110*/ { "CMSG_UNCLAIM_LICENSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x111*/ { "CMSG_DESTROYITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDestroyItemOpcode }, - /*0x112*/ { "SMSG_INVENTORY_CHANGE_FAILURE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x113*/ { "SMSG_OPEN_CONTAINER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x114*/ { "CMSG_INSPECT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectOpcode }, - /*0x115*/ { "SMSG_INSPECT_RESULTS_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x116*/ { "CMSG_INITIATE_TRADE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInitiateTradeOpcode }, - /*0x117*/ { "CMSG_BEGIN_TRADE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBeginTradeOpcode }, - /*0x118*/ { "CMSG_BUSY_TRADE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBusyTradeOpcode }, - /*0x119*/ { "CMSG_IGNORE_TRADE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleIgnoreTradeOpcode }, - /*0x11A*/ { "CMSG_ACCEPT_TRADE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptTradeOpcode }, - /*0x11B*/ { "CMSG_UNACCEPT_TRADE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode }, - /*0x11C*/ { "CMSG_CANCEL_TRADE", STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTradeOpcode }, - /*0x11D*/ { "CMSG_SET_TRADE_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeItemOpcode }, - /*0x11E*/ { "CMSG_CLEAR_TRADE_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleClearTradeItemOpcode }, - /*0x11F*/ { "CMSG_SET_TRADE_GOLD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeGoldOpcode }, - /*0x120*/ { "SMSG_TRADE_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x121*/ { "SMSG_TRADE_STATUS_EXTENDED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x122*/ { "SMSG_INITIALIZE_FACTIONS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x123*/ { "SMSG_SET_FACTION_VISIBLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x124*/ { "SMSG_SET_FACTION_STANDING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x125*/ { "CMSG_SET_FACTION_ATWAR", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetFactionAtWar }, - /*0x126*/ { "CMSG_SET_FACTION_CHEAT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetFactionCheat }, - /*0x127*/ { "SMSG_SET_PROFICIENCY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x128*/ { "CMSG_SET_ACTION_BUTTON", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActionButtonOpcode }, - /*0x129*/ { "SMSG_ACTION_BUTTONS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x12A*/ { "SMSG_INITIAL_SPELLS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x12B*/ { "SMSG_LEARNED_SPELL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x12C*/ { "SMSG_SUPERCEDED_SPELL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x12D*/ { "CMSG_NEW_SPELL_SLOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x12E*/ { "CMSG_CAST_SPELL", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleCastSpellOpcode }, - /*0x12F*/ { "CMSG_CANCEL_CAST", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleCancelCastOpcode }, - /*0x130*/ { "SMSG_CAST_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x131*/ { "SMSG_SPELL_START", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x132*/ { "SMSG_SPELL_GO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x133*/ { "SMSG_SPELL_FAILURE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x134*/ { "SMSG_SPELL_COOLDOWN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x135*/ { "SMSG_COOLDOWN_EVENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x136*/ { "CMSG_CANCEL_AURA", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelAuraOpcode }, - /*0x137*/ { "SMSG_EQUIPMENT_SET_SAVED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x138*/ { "SMSG_PET_CAST_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x139*/ { "MSG_CHANNEL_START", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x13A*/ { "MSG_CHANNEL_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x13B*/ { "CMSG_CANCEL_CHANNELLING", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelChanneling }, - /*0x13C*/ { "SMSG_AI_REACTION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x13D*/ { "CMSG_SET_SELECTION", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSetSelectionOpcode }, - /*0x13E*/ { "CMSG_DELETEEQUIPMENT_SET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetDelete }, - /*0x13F*/ { "CMSG_INSTANCE_LOCK_RESPONSE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInstanceLockResponse }, - /*0x140*/ { "CMSG_DEBUG_PASSIVE_AURA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x141*/ { "CMSG_ATTACKSWING", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleAttackSwingOpcode }, - /*0x142*/ { "CMSG_ATTACKSTOP", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleAttackStopOpcode }, - /*0x143*/ { "SMSG_ATTACKSTART", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x144*/ { "SMSG_ATTACKSTOP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x145*/ { "SMSG_ATTACKSWING_NOTINRANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x146*/ { "SMSG_ATTACKSWING_BADFACING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x147*/ { "SMSG_INSTANCE_LOCK_WARNING_QUERY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x148*/ { "SMSG_ATTACKSWING_DEADTARGET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x149*/ { "SMSG_ATTACKSWING_CANT_ATTACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x14A*/ { "SMSG_ATTACKERSTATEUPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x14B*/ { "SMSG_BATTLEFIELD_PORT_DENIED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x14C*/ { "CMSG_PERFORM_ACTION_SET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x14D*/ { "SMSG_RESUME_CAST_BAR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x14E*/ { "SMSG_CANCEL_COMBAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x14F*/ { "SMSG_SPELLBREAKLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x150*/ { "SMSG_SPELLHEALLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x151*/ { "SMSG_SPELLENERGIZELOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x152*/ { "SMSG_BREAK_TARGET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x153*/ { "CMSG_SAVE_PLAYER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x154*/ { "CMSG_SETDEATHBINDPOINT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x155*/ { "SMSG_BINDPOINTUPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x156*/ { "CMSG_GETDEATHBINDZONE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x157*/ { "SMSG_BINDZONEREPLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x158*/ { "SMSG_PLAYERBOUND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x159*/ { "SMSG_CLIENT_CONTROL_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x15A*/ { "CMSG_REPOP_REQUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRepopRequestOpcode }, - /*0x15B*/ { "SMSG_RESURRECT_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x15C*/ { "CMSG_RESURRECT_RESPONSE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleResurrectResponseOpcode }, - /*0x15D*/ { "CMSG_LOOT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootOpcode }, - /*0x15E*/ { "CMSG_LOOT_MONEY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMoneyOpcode }, - /*0x15F*/ { "CMSG_LOOT_RELEASE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootReleaseOpcode }, - /*0x160*/ { "SMSG_LOOT_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x161*/ { "SMSG_LOOT_RELEASE_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x162*/ { "SMSG_LOOT_REMOVED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x163*/ { "SMSG_LOOT_MONEY_NOTIFY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x164*/ { "SMSG_LOOT_ITEM_NOTIFY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x165*/ { "SMSG_LOOT_CLEAR_MONEY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x166*/ { "SMSG_ITEM_PUSH_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x167*/ { "SMSG_DUEL_REQUESTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x168*/ { "SMSG_DUEL_OUTOFBOUNDS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x169*/ { "SMSG_DUEL_INBOUNDS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x16A*/ { "SMSG_DUEL_COMPLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x16B*/ { "SMSG_DUEL_WINNER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x16C*/ { "CMSG_DUEL_ACCEPTED", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDuelAcceptedOpcode }, - /*0x16D*/ { "CMSG_DUEL_CANCELLED", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDuelCancelledOpcode }, - /*0x16E*/ { "SMSG_MOUNTRESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x16F*/ { "SMSG_DISMOUNTRESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x170*/ { "SMSG_REMOVED_FROM_PVP_QUEUE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x171*/ { "CMSG_MOUNTSPECIAL_ANIM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMountSpecialAnimOpcode }, - /*0x172*/ { "SMSG_MOUNTSPECIAL_ANIM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x173*/ { "SMSG_PET_TAME_FAILURE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x174*/ { "CMSG_PET_SET_ACTION", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSetAction }, - /*0x175*/ { "CMSG_PET_ACTION", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetAction }, - /*0x176*/ { "CMSG_PET_ABANDON", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetAbandon }, - /*0x177*/ { "CMSG_PET_RENAME", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetRename }, - /*0x178*/ { "SMSG_PET_NAME_INVALID", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x179*/ { "SMSG_PET_SPELLS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x17A*/ { "SMSG_PET_MODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x17B*/ { "CMSG_GOSSIP_HELLO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGossipHelloOpcode }, - /*0x17C*/ { "CMSG_GOSSIP_SELECT_OPTION", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGossipSelectOptionOpcode }, - /*0x17D*/ { "SMSG_GOSSIP_MESSAGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x17E*/ { "SMSG_GOSSIP_COMPLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x17F*/ { "CMSG_NPC_TEXT_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNpcTextQueryOpcode }, - /*0x180*/ { "SMSG_NPC_TEXT_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x181*/ { "SMSG_NPC_WONT_TALK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x182*/ { "CMSG_QUESTGIVER_STATUS_QUERY", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleQuestgiverStatusQueryOpcode}, - /*0x183*/ { "SMSG_QUESTGIVER_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x184*/ { "CMSG_QUESTGIVER_HELLO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverHelloOpcode }, - /*0x185*/ { "SMSG_QUESTGIVER_QUEST_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x186*/ { "CMSG_QUESTGIVER_QUERY_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverQueryQuestOpcode}, - /*0x187*/ { "CMSG_QUESTGIVER_QUEST_AUTOLAUNCH", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverQuestAutoLaunch }, - /*0x188*/ { "SMSG_QUESTGIVER_QUEST_DETAILS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x189*/ { "CMSG_QUESTGIVER_ACCEPT_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverAcceptQuestOpcode}, - /*0x18A*/ { "CMSG_QUESTGIVER_COMPLETE_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverCompleteQuest }, - /*0x18B*/ { "SMSG_QUESTGIVER_REQUEST_ITEMS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x18C*/ { "CMSG_QUESTGIVER_REQUEST_REWARD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverRequestRewardOpcode}, - /*0x18D*/ { "SMSG_QUESTGIVER_OFFER_REWARD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x18E*/ { "CMSG_QUESTGIVER_CHOOSE_REWARD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverChooseRewardOpcode}, - /*0x18F*/ { "SMSG_QUESTGIVER_QUEST_INVALID", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x190*/ { "CMSG_QUESTGIVER_CANCEL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverCancel }, - /*0x191*/ { "SMSG_QUESTGIVER_QUEST_COMPLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x192*/ { "SMSG_QUESTGIVER_QUEST_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x193*/ { "CMSG_QUESTLOG_SWAP_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestLogSwapQuest }, - /*0x194*/ { "CMSG_QUESTLOG_REMOVE_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestLogRemoveQuest }, - /*0x195*/ { "SMSG_QUESTLOG_FULL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x196*/ { "SMSG_QUESTUPDATE_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x197*/ { "SMSG_QUESTUPDATE_FAILEDTIMER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x198*/ { "SMSG_QUESTUPDATE_COMPLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x199*/ { "SMSG_QUESTUPDATE_ADD_KILL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x19A*/ { "SMSG_QUESTUPDATE_ADD_ITEM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x19B*/ { "CMSG_QUEST_CONFIRM_ACCEPT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestConfirmAccept }, - /*0x19C*/ { "SMSG_QUEST_CONFIRM_ACCEPT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x19D*/ { "CMSG_PUSHQUESTTOPARTY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePushQuestToParty }, - /*0x19E*/ { "CMSG_LIST_INVENTORY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleListInventoryOpcode }, - /*0x19F*/ { "SMSG_LIST_INVENTORY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1A0*/ { "CMSG_SELL_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSellItemOpcode }, - /*0x1A1*/ { "SMSG_SELL_ITEM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1A2*/ { "CMSG_BUY_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyItemOpcode }, - /*0x1A3*/ { "CMSG_BUY_ITEM_IN_SLOT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyItemInSlotOpcode }, - /*0x1A4*/ { "SMSG_BUY_ITEM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1A5*/ { "SMSG_BUY_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1A6*/ { "CMSG_TAXICLEARALLNODES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1A7*/ { "CMSG_TAXIENABLEALLNODES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1A8*/ { "CMSG_TAXISHOWNODES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1A9*/ { "SMSG_SHOWTAXINODES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1AA*/ { "CMSG_TAXINODE_STATUS_QUERY", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiNodeStatusQueryOpcode }, - /*0x1AB*/ { "SMSG_TAXINODE_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1AC*/ { "CMSG_TAXIQUERYAVAILABLENODES", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes }, - /*0x1AD*/ { "CMSG_ACTIVATETAXI", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleActivateTaxiOpcode }, - /*0x1AE*/ { "SMSG_ACTIVATETAXIREPLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1AF*/ { "SMSG_NEW_TAXI_PATH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1B0*/ { "CMSG_TRAINER_LIST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerListOpcode }, - /*0x1B1*/ { "SMSG_TRAINER_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1B2*/ { "CMSG_TRAINER_BUY_SPELL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerBuySpellOpcode }, - /*0x1B3*/ { "SMSG_TRAINER_BUY_SUCCEEDED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1B4*/ { "SMSG_TRAINER_BUY_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1B5*/ { "CMSG_BINDER_ACTIVATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBinderActivateOpcode }, - /*0x1B6*/ { "SMSG_PLAYERBINDERROR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1B7*/ { "CMSG_BANKER_ACTIVATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBankerActivateOpcode }, - /*0x1B8*/ { "SMSG_SHOW_BANK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1B9*/ { "CMSG_BUY_BANK_SLOT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyBankSlotOpcode }, - /*0x1BA*/ { "SMSG_BUY_BANK_SLOT_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1BB*/ { "CMSG_PETITION_SHOWLIST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionShowListOpcode }, - /*0x1BC*/ { "SMSG_PETITION_SHOWLIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1BD*/ { "CMSG_PETITION_BUY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionBuyOpcode }, - /*0x1BE*/ { "CMSG_PETITION_SHOW_SIGNATURES", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionShowSignOpcode }, - /*0x1BF*/ { "SMSG_PETITION_SHOW_SIGNATURES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1C0*/ { "CMSG_PETITION_SIGN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionSignOpcode }, - /*0x1C1*/ { "SMSG_PETITION_SIGN_RESULTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1C2*/ { "MSG_PETITION_DECLINE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionDeclineOpcode }, - /*0x1C3*/ { "CMSG_OFFER_PETITION", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleOfferPetitionOpcode }, - /*0x1C4*/ { "CMSG_TURN_IN_PETITION", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTurnInPetitionOpcode }, - /*0x1C5*/ { "SMSG_TURN_IN_PETITION_RESULTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1C6*/ { "CMSG_PETITION_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionQueryOpcode }, - /*0x1C7*/ { "SMSG_PETITION_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1C8*/ { "SMSG_FISH_NOT_HOOKED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1C9*/ { "SMSG_FISH_ESCAPED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1CA*/ { "CMSG_BUG", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBugOpcode }, - /*0x1CB*/ { "SMSG_NOTIFICATION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1CC*/ { "CMSG_PLAYED_TIME", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePlayedTime }, - /*0x1CD*/ { "SMSG_PLAYED_TIME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1CE*/ { "CMSG_QUERY_TIME", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryTimeOpcode }, - /*0x1CF*/ { "SMSG_QUERY_TIME_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1D0*/ { "SMSG_LOG_XPGAIN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1D1*/ { "SMSG_AURACASTLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1D2*/ { "CMSG_RECLAIM_CORPSE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReclaimCorpseOpcode }, - /*0x1D3*/ { "CMSG_WRAP_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWrapItemOpcode }, - /*0x1D4*/ { "SMSG_LEVELUP_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1D5*/ { "MSG_MINIMAP_PING", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMinimapPingOpcode }, - /*0x1D6*/ { "SMSG_RESISTLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1D7*/ { "SMSG_ENCHANTMENTLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1D8*/ { "CMSG_SET_SKILL_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1D9*/ { "SMSG_START_MIRROR_TIMER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1DA*/ { "SMSG_PAUSE_MIRROR_TIMER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1DB*/ { "SMSG_STOP_MIRROR_TIMER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1DC*/ { "CMSG_PING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess }, - /*0x1DD*/ { "SMSG_PONG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1DE*/ { "SMSG_CLEAR_COOLDOWN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1DF*/ { "SMSG_GAMEOBJECT_PAGETEXT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1E0*/ { "CMSG_SETSHEATHED", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSetSheathedOpcode }, - /*0x1E1*/ { "SMSG_COOLDOWN_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1E2*/ { "SMSG_SPELL_DELAYED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1E3*/ { "CMSG_QUEST_POI_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPOIQuery }, - /*0x1E4*/ { "SMSG_QUEST_POI_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1E5*/ { "CMSG_GHOST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1E6*/ { "CMSG_GM_INVIS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1E7*/ { "SMSG_INVALID_PROMOTION_CODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1E8*/ { "MSG_GM_BIND_OTHER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1E9*/ { "MSG_GM_SUMMON", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1EA*/ { "SMSG_ITEM_TIME_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1EB*/ { "SMSG_ITEM_ENCHANT_TIME_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1EC*/ { "SMSG_AUTH_CHALLENGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1ED*/ { "CMSG_AUTH_SESSION", STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess }, - /*0x1EE*/ { "SMSG_AUTH_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1EF*/ { "MSG_GM_SHOWLABEL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1F0*/ { "CMSG_PET_CAST_SPELL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCastSpellOpcode }, - /*0x1F1*/ { "MSG_SAVE_GUILD_EMBLEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSaveGuildEmblemOpcode }, - /*0x1F2*/ { "MSG_TABARDVENDOR_ACTIVATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTabardVendorActivateOpcode}, - /*0x1F3*/ { "SMSG_PLAY_SPELL_VISUAL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1F4*/ { "CMSG_ZONEUPDATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleZoneUpdateOpcode }, - /*0x1F5*/ { "SMSG_PARTYKILLLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1F6*/ { "SMSG_COMPRESSED_UPDATE_OBJECT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1F7*/ { "SMSG_PLAY_SPELL_IMPACT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1F8*/ { "SMSG_EXPLORATION_EXPERIENCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1F9*/ { "CMSG_GM_SET_SECURITY_GROUP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1FA*/ { "CMSG_GM_NUKE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1FB*/ { "MSG_RANDOM_ROLL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRandomRollOpcode }, - /*0x1FC*/ { "SMSG_ENVIRONMENTALDAMAGELOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1FD*/ { "CMSG_CHANGEPLAYER_DIFFICULTY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x1FE*/ { "SMSG_RWHOIS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x1FF*/ { "SMSG_LFG_PLAYER_REWARD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x200*/ { "SMSG_LFG_TELEPORT_DENIED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x201*/ { "CMSG_UNLEARN_SPELL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x202*/ { "CMSG_UNLEARN_SKILL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnlearnSkillOpcode }, - /*0x203*/ { "SMSG_REMOVED_SPELL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x204*/ { "CMSG_DECHARGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x205*/ { "CMSG_GMTICKET_CREATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketCreateOpcode }, - /*0x206*/ { "SMSG_GMTICKET_CREATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x207*/ { "CMSG_GMTICKET_UPDATETEXT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketUpdateOpcode }, - /*0x208*/ { "SMSG_GMTICKET_UPDATETEXT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x209*/ { "SMSG_ACCOUNT_DATA_TIMES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x20A*/ { "CMSG_REQUEST_ACCOUNT_DATA", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestAccountData }, - /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateAccountData }, - /*0x20C*/ { "SMSG_UPDATE_ACCOUNT_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x20D*/ { "SMSG_CLEAR_FAR_SIGHT_IMMEDIATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x20E*/ { "SMSG_CHANGEPLAYER_DIFFICULTY_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x20F*/ { "CMSG_GM_TEACH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x210*/ { "CMSG_GM_CREATE_ITEM_TARGET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x211*/ { "CMSG_GMTICKET_GETTICKET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketGetTicketOpcode }, - /*0x212*/ { "SMSG_GMTICKET_GETTICKET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x213*/ { "CMSG_UNLEARN_TALENTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x214*/ { "SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x215*/ { "SMSG_GAMEOBJECT_DESPAWN_ANIM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x216*/ { "MSG_CORPSE_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCorpseQueryOpcode }, - /*0x217*/ { "CMSG_GMTICKET_DELETETICKET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketDeleteOpcode }, - /*0x218*/ { "SMSG_GMTICKET_DELETETICKET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x219*/ { "SMSG_CHAT_WRONG_FACTION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x21A*/ { "CMSG_GMTICKET_SYSTEMSTATUS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketSystemStatusOpcode}, - /*0x21B*/ { "SMSG_GMTICKET_SYSTEMSTATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x21C*/ { "CMSG_SPIRIT_HEALER_ACTIVATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSpiritHealerActivateOpcode}, - /*0x21D*/ { "CMSG_SET_STAT_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x21E*/ { "SMSG_QUEST_FORCE_REMOVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x21F*/ { "CMSG_SKILL_BUY_STEP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x220*/ { "CMSG_SKILL_BUY_RANK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x221*/ { "CMSG_XP_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x222*/ { "SMSG_SPIRIT_HEALER_CONFIRM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x223*/ { "CMSG_CHARACTER_POINT_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x224*/ { "SMSG_GOSSIP_POI", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x225*/ { "CMSG_CHAT_IGNORED", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChatIgnoredOpcode }, - /*0x226*/ { "CMSG_GM_VISION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x227*/ { "CMSG_SERVER_COMMAND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x228*/ { "CMSG_GM_SILENCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x229*/ { "CMSG_GM_REVEALTO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x22A*/ { "CMSG_GM_RESURRECT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x22B*/ { "CMSG_GM_SUMMONMOB", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x22C*/ { "CMSG_GM_MOVECORPSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x22D*/ { "CMSG_GM_FREEZE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x22E*/ { "CMSG_GM_UBERINVIS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x22F*/ { "CMSG_GM_REQUEST_PLAYER_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x230*/ { "SMSG_GM_PLAYER_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x231*/ { "CMSG_GUILD_RANK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildRankOpcode }, - /*0x232*/ { "CMSG_GUILD_ADD_RANK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildAddRankOpcode }, - /*0x233*/ { "CMSG_GUILD_DEL_RANK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildDelRankOpcode }, - /*0x234*/ { "CMSG_GUILD_SET_PUBLIC_NOTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildSetPublicNoteOpcode }, - /*0x235*/ { "CMSG_GUILD_SET_OFFICER_NOTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildSetOfficerNoteOpcode }, - /*0x236*/ { "SMSG_LOGIN_VERIFY_WORLD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x237*/ { "CMSG_CLEAR_EXPLORATION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x238*/ { "CMSG_SEND_MAIL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSendMail }, - /*0x239*/ { "SMSG_SEND_MAIL_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x23A*/ { "CMSG_GET_MAIL_LIST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetMailList }, - /*0x23B*/ { "SMSG_MAIL_LIST_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x23C*/ { "CMSG_BATTLEFIELD_LIST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlefieldListOpcode }, - /*0x23D*/ { "SMSG_BATTLEFIELD_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x23E*/ { "CMSG_BATTLEFIELD_JOIN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x23F*/ { "SMSG_FORCE_SET_VEHICLE_REC_ID", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x240*/ { "CMSG_SET_VEHICLE_REC_ID_ACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x241*/ { "CMSG_TAXICLEARNODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x242*/ { "CMSG_TAXIENABLENODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x243*/ { "CMSG_ITEM_TEXT_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleItemTextQuery }, - /*0x244*/ { "SMSG_ITEM_TEXT_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x245*/ { "CMSG_MAIL_TAKE_MONEY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailTakeMoney }, - /*0x246*/ { "CMSG_MAIL_TAKE_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailTakeItem }, - /*0x247*/ { "CMSG_MAIL_MARK_AS_READ", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailMarkAsRead }, - /*0x248*/ { "CMSG_MAIL_RETURN_TO_SENDER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailReturnToSender }, - /*0x249*/ { "CMSG_MAIL_DELETE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailDelete }, - /*0x24A*/ { "CMSG_MAIL_CREATE_TEXT_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailCreateTextItem }, - /*0x24B*/ { "SMSG_SPELLLOGMISS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x24C*/ { "SMSG_SPELLLOGEXECUTE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x24D*/ { "SMSG_DEBUGAURAPROC", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x24E*/ { "SMSG_PERIODICAURALOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x24F*/ { "SMSG_SPELLDAMAGESHIELD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x250*/ { "SMSG_SPELLNONMELEEDAMAGELOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x251*/ { "CMSG_LEARN_TALENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnTalentOpcode }, - /*0x252*/ { "SMSG_RESURRECT_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x253*/ { "CMSG_TOGGLE_PVP", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTogglePvP }, - /*0x254*/ { "SMSG_ZONE_UNDER_ATTACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x255*/ { "MSG_AUCTION_HELLO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionHelloOpcode }, - /*0x256*/ { "CMSG_AUCTION_SELL_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionSellItem }, - /*0x257*/ { "CMSG_AUCTION_REMOVE_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionRemoveItem }, - /*0x258*/ { "CMSG_AUCTION_LIST_ITEMS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListItems }, - /*0x259*/ { "CMSG_AUCTION_LIST_OWNER_ITEMS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListOwnerItems }, - /*0x25A*/ { "CMSG_AUCTION_PLACE_BID", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionPlaceBid }, - /*0x25B*/ { "SMSG_AUCTION_COMMAND_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x25C*/ { "SMSG_AUCTION_LIST_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x25D*/ { "SMSG_AUCTION_OWNER_LIST_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x25E*/ { "SMSG_AUCTION_BIDDER_NOTIFICATION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x25F*/ { "SMSG_AUCTION_OWNER_NOTIFICATION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x260*/ { "SMSG_PROCRESIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x261*/ { "SMSG_COMBAT_EVENT_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x262*/ { "SMSG_DISPEL_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x263*/ { "SMSG_SPELLORDAMAGE_IMMUNE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x264*/ { "CMSG_AUCTION_LIST_BIDDER_ITEMS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListBidderItems }, - /*0x265*/ { "SMSG_AUCTION_BIDDER_LIST_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x266*/ { "SMSG_SET_FLAT_SPELL_MODIFIER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x267*/ { "SMSG_SET_PCT_SPELL_MODIFIER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x268*/ { "CMSG_SET_AMMO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetAmmoOpcode }, - /*0x269*/ { "SMSG_CORPSE_RECLAIM_DELAY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x26A*/ { "CMSG_SET_ACTIVE_MOVER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveMoverOpcode }, - /*0x26B*/ { "CMSG_PET_CANCEL_AURA", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCancelAuraOpcode }, - /*0x26C*/ { "CMSG_PLAYER_AI_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x26D*/ { "CMSG_CANCEL_AUTO_REPEAT_SPELL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelAutoRepeatSpellOpcode}, - /*0x26E*/ { "MSG_GM_ACCOUNT_ONLINE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x26F*/ { "MSG_LIST_STABLED_PETS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode }, - /*0x270*/ { "CMSG_STABLE_PET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleStablePet }, - /*0x271*/ { "CMSG_UNSTABLE_PET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnstablePet }, - /*0x272*/ { "CMSG_BUY_STABLE_SLOT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyStableSlot }, - /*0x273*/ { "SMSG_STABLE_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x274*/ { "CMSG_STABLE_REVIVE_PET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleStableRevivePet }, - /*0x275*/ { "CMSG_STABLE_SWAP_PET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleStableSwapPet }, - /*0x276*/ { "MSG_QUEST_PUSH_RESULT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPushResult }, - /*0x277*/ { "SMSG_PLAY_MUSIC", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x278*/ { "SMSG_PLAY_OBJECT_SOUND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x279*/ { "CMSG_REQUEST_PET_INFO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPetInfoOpcode }, - /*0x27A*/ { "CMSG_FAR_SIGHT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleFarSightOpcode }, - /*0x27B*/ { "SMSG_SPELLDISPELLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x27C*/ { "SMSG_DAMAGE_CALC_LOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x27D*/ { "CMSG_ENABLE_DAMAGE_LOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x27E*/ { "CMSG_GROUP_CHANGE_SUB_GROUP", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupChangeSubGroupOpcode }, - /*0x27F*/ { "CMSG_REQUEST_PARTY_MEMBER_STATS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPartyMemberStatsOpcode}, - /*0x280*/ { "CMSG_GROUP_SWAP_SUB_GROUP", STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x281*/ { "CMSG_RESET_FACTION_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x282*/ { "CMSG_AUTOSTORE_BANK_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBankItemOpcode }, - /*0x283*/ { "CMSG_AUTOBANK_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoBankItemOpcode }, - /*0x284*/ { "MSG_QUERY_NEXT_MAIL_TIME", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryNextMailTime }, - /*0x285*/ { "SMSG_RECEIVED_MAIL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x286*/ { "SMSG_RAID_GROUP_ONLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x287*/ { "CMSG_SET_DURABILITY_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x288*/ { "CMSG_SET_PVP_RANK_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x289*/ { "CMSG_ADD_PVP_MEDAL_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x28A*/ { "CMSG_DEL_PVP_MEDAL_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x28B*/ { "CMSG_SET_PVP_TITLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x28C*/ { "SMSG_PVP_CREDIT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x28D*/ { "SMSG_AUCTION_REMOVED_NOTIFICATION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x28E*/ { "CMSG_GROUP_RAID_CONVERT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupRaidConvertOpcode }, - /*0x28F*/ { "CMSG_GROUP_ASSISTANT_LEADER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupAssistantLeaderOpcode}, - /*0x290*/ { "CMSG_BUYBACK_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuybackItem }, - /*0x291*/ { "SMSG_SERVER_MESSAGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x292*/ { "CMSG_SET_SAVED_INSTANCE_EXTEND", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetSavedInstanceExtend }, - /*0x293*/ { "SMSG_LFG_OFFER_CONTINUE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x294*/ { "CMSG_TEST_DROP_RATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x295*/ { "SMSG_TEST_DROP_RATE_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x296*/ { "CMSG_LFG_GET_STATUS", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleLfgGetStatus }, - /*0x297*/ { "SMSG_SHOW_MAILBOX", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x298*/ { "SMSG_RESET_RANGED_COMBAT_TIMER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x299*/ { "SMSG_MEETINGSTONE_MEMBER_ADDED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x29A*/ { "SMSG_CHAT_NOT_IN_PARTY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x29B*/ { "CMSG_CANCEL_GROWTH_AURA", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelGrowthAuraOpcode }, - /*0x29C*/ { "SMSG_CANCEL_AUTO_REPEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x29D*/ { "SMSG_STANDSTATE_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x29E*/ { "SMSG_LOOT_ALL_PASSED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x29F*/ { "SMSG_LOOT_ROLL_WON", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2A0*/ { "CMSG_LOOT_ROLL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootRoll }, - /*0x2A1*/ { "SMSG_LOOT_START_ROLL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2A2*/ { "SMSG_LOOT_ROLL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2A3*/ { "CMSG_LOOT_MASTER_GIVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMasterGiveOpcode }, - /*0x2A4*/ { "SMSG_LOOT_MASTER_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2A5*/ { "SMSG_SET_FORCED_REACTIONS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2A6*/ { "SMSG_SPELL_FAILED_OTHER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2A7*/ { "SMSG_GAMEOBJECT_RESET_STATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2A8*/ { "CMSG_REPAIR_ITEM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRepairItemOpcode }, - /*0x2A9*/ { "SMSG_CHAT_PLAYER_NOT_FOUND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2AA*/ { "MSG_TALENT_WIPE_CONFIRM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTalentWipeConfirmOpcode }, - /*0x2AB*/ { "SMSG_SUMMON_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2AC*/ { "CMSG_SUMMON_RESPONSE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode }, - /*0x2AD*/ { "MSG_DEV_SHOWLABEL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2AE*/ { "SMSG_MONSTER_MOVE_TRANSPORT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2AF*/ { "SMSG_PET_BROKEN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2B0*/ { "MSG_MOVE_FEATHER_FALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2B1*/ { "MSG_MOVE_WATER_WALK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2B2*/ { "CMSG_SERVER_BROADCAST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2B3*/ { "CMSG_SELF_RES", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSelfResOpcode }, - /*0x2B4*/ { "SMSG_FEIGN_DEATH_RESISTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2B5*/ { "CMSG_RUN_SCRIPT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2B6*/ { "SMSG_SCRIPT_MESSAGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2B7*/ { "SMSG_DUEL_COUNTDOWN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2B8*/ { "SMSG_AREA_TRIGGER_MESSAGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2B9*/ { "CMSG_SHOWING_HELM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleShowingHelmOpcode }, - /*0x2BA*/ { "CMSG_SHOWING_CLOAK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleShowingCloakOpcode }, - /*0x2BB*/ { "SMSG_LFG_ROLE_CHOSEN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2BC*/ { "SMSG_PLAYER_SKINNED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2BD*/ { "SMSG_DURABILITY_DAMAGE_DEATH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2BE*/ { "CMSG_SET_EXPLORATION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2BF*/ { "CMSG_SET_ACTIONBAR_TOGGLES", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActionBarToggles }, - /*0x2C0*/ { "UMSG_DELETE_GUILD_CHARTER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2C1*/ { "MSG_PETITION_RENAME", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionRenameOpcode }, - /*0x2C2*/ { "SMSG_INIT_WORLD_STATES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2C3*/ { "SMSG_UPDATE_WORLD_STATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2C4*/ { "CMSG_ITEM_NAME_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleItemNameQueryOpcode }, - /*0x2C5*/ { "SMSG_ITEM_NAME_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2C6*/ { "SMSG_PET_ACTION_FEEDBACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2C7*/ { "CMSG_CHAR_RENAME", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharRenameOpcode }, - /*0x2C8*/ { "SMSG_CHAR_RENAME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2C9*/ { "CMSG_MOVE_SPLINE_DONE", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSplineDoneOpcode }, - /*0x2CA*/ { "CMSG_MOVE_FALL_RESET", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x2CB*/ { "SMSG_INSTANCE_SAVE_CREATED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2CC*/ { "SMSG_RAID_INSTANCE_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2CD*/ { "CMSG_REQUEST_RAID_INFO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRaidInfoOpcode }, - /*0x2CE*/ { "CMSG_MOVE_TIME_SKIPPED", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleMoveTimeSkippedOpcode }, - /*0x2CF*/ { "CMSG_MOVE_FEATHER_FALL_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleFeatherFallAck }, - /*0x2D0*/ { "CMSG_MOVE_WATER_WALK_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveWaterWalkAck }, - /*0x2D1*/ { "CMSG_MOVE_NOT_ACTIVE_MOVER", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveNotActiveMover }, - /*0x2D2*/ { "SMSG_PLAY_SOUND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2D3*/ { "CMSG_BATTLEFIELD_STATUS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlefieldStatusOpcode }, - /*0x2D4*/ { "SMSG_BATTLEFIELD_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2D5*/ { "CMSG_BATTLEFIELD_PORT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattleFieldPortOpcode }, - /*0x2D6*/ { "MSG_INSPECT_HONOR_STATS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectHonorStatsOpcode }, - /*0x2D7*/ { "CMSG_BATTLEMASTER_HELLO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlemasterHelloOpcode }, - /*0x2D8*/ { "CMSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2D9*/ { "CMSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2DA*/ { "SMSG_FORCE_WALK_SPEED_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2DB*/ { "CMSG_FORCE_WALK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck }, - /*0x2DC*/ { "SMSG_FORCE_SWIM_BACK_SPEED_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2DD*/ { "CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck }, - /*0x2DE*/ { "SMSG_FORCE_TURN_RATE_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2DF*/ { "CMSG_FORCE_TURN_RATE_CHANGE_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck }, - /*0x2E0*/ { "MSG_PVP_LOG_DATA", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePVPLogDataOpcode }, - /*0x2E1*/ { "CMSG_LEAVE_BATTLEFIELD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlefieldLeaveOpcode }, - /*0x2E2*/ { "CMSG_AREA_SPIRIT_HEALER_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaSpiritHealerQueryOpcode}, - /*0x2E3*/ { "CMSG_AREA_SPIRIT_HEALER_QUEUE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaSpiritHealerQueueOpcode}, - /*0x2E4*/ { "SMSG_AREA_SPIRIT_HEALER_TIME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2E5*/ { "CMSG_GM_UNTEACH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2E6*/ { "SMSG_WARDEN_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2E7*/ { "CMSG_WARDEN_DATA", STATUS_AUTHED, PROCESS_THREADSAFE, &WorldSession::HandleWardenDataOpcode }, - /*0x2E8*/ { "SMSG_GROUP_JOINED_BATTLEGROUND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2E9*/ { "MSG_BATTLEGROUND_PLAYER_POSITIONS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlegroundPlayerPositionsOpcode}, - /*0x2EA*/ { "CMSG_PET_STOP_ATTACK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetStopAttack }, - /*0x2EB*/ { "SMSG_BINDER_CONFIRM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2EC*/ { "SMSG_BATTLEGROUND_PLAYER_JOINED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2ED*/ { "SMSG_BATTLEGROUND_PLAYER_LEFT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2EE*/ { "CMSG_BATTLEMASTER_JOIN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlemasterJoinOpcode }, - /*0x2EF*/ { "SMSG_ADDON_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2F0*/ { "CMSG_PET_UNLEARN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2F1*/ { "SMSG_PET_UNLEARN_CONFIRM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2F2*/ { "SMSG_PARTY_MEMBER_STATS_FULL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2F3*/ { "CMSG_PET_SPELL_AUTOCAST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSpellAutocastOpcode }, - /*0x2F4*/ { "SMSG_WEATHER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2F5*/ { "SMSG_PLAY_TIME_WARNING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2F6*/ { "SMSG_MINIGAME_SETUP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2F7*/ { "SMSG_MINIGAME_STATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2F8*/ { "CMSG_MINIGAME_MOVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x2F9*/ { "SMSG_MINIGAME_MOVE_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2FA*/ { "SMSG_RAID_INSTANCE_MESSAGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2FB*/ { "SMSG_COMPRESSED_MOVES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2FC*/ { "CMSG_GUILD_INFO_TEXT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildChangeInfoTextOpcode }, - /*0x2FD*/ { "SMSG_CHAT_RESTRICTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2FE*/ { "SMSG_SPLINE_SET_RUN_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x2FF*/ { "SMSG_SPLINE_SET_RUN_BACK_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x300*/ { "SMSG_SPLINE_SET_SWIM_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x301*/ { "SMSG_SPLINE_SET_WALK_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x302*/ { "SMSG_SPLINE_SET_SWIM_BACK_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x303*/ { "SMSG_SPLINE_SET_TURN_RATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x304*/ { "SMSG_SPLINE_MOVE_UNROOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x305*/ { "SMSG_SPLINE_MOVE_FEATHER_FALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x306*/ { "SMSG_SPLINE_MOVE_NORMAL_FALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x307*/ { "SMSG_SPLINE_MOVE_SET_HOVER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x308*/ { "SMSG_SPLINE_MOVE_UNSET_HOVER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x309*/ { "SMSG_SPLINE_MOVE_WATER_WALK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x30A*/ { "SMSG_SPLINE_MOVE_LAND_WALK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x30B*/ { "SMSG_SPLINE_MOVE_START_SWIM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x30C*/ { "SMSG_SPLINE_MOVE_STOP_SWIM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x30D*/ { "SMSG_SPLINE_MOVE_SET_RUN_MODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x30E*/ { "SMSG_SPLINE_MOVE_SET_WALK_MODE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x30F*/ { "CMSG_GM_NUKE_ACCOUNT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x310*/ { "MSG_GM_DESTROY_CORPSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x311*/ { "CMSG_GM_DESTROY_ONLINE_CORPSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x312*/ { "CMSG_ACTIVATETAXIEXPRESS", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleActivateTaxiExpressOpcode }, - /*0x313*/ { "SMSG_SET_FACTION_ATWAR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x314*/ { "SMSG_GAMETIMEBIAS_SET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x315*/ { "CMSG_DEBUG_ACTIONS_START", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x316*/ { "CMSG_DEBUG_ACTIONS_STOP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x317*/ { "CMSG_SET_FACTION_INACTIVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetFactionInactiveOpcode }, - /*0x318*/ { "CMSG_SET_WATCHED_FACTION", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetWatchedFactionOpcode }, - /*0x319*/ { "MSG_MOVE_TIME_SKIPPED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x31A*/ { "SMSG_SPLINE_MOVE_ROOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x31B*/ { "CMSG_SET_EXPLORATION_ALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x31C*/ { "SMSG_INVALIDATE_PLAYER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x31D*/ { "CMSG_RESET_INSTANCES", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleResetInstancesOpcode }, - /*0x31E*/ { "SMSG_INSTANCE_RESET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x31F*/ { "SMSG_INSTANCE_RESET_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x320*/ { "SMSG_UPDATE_LAST_INSTANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x321*/ { "MSG_RAID_TARGET_UPDATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidTargetUpdateOpcode }, - /*0x322*/ { "MSG_RAID_READY_CHECK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidReadyCheckOpcode }, - /*0x323*/ { "CMSG_LUA_USAGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x324*/ { "SMSG_PET_ACTION_SOUND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x325*/ { "SMSG_PET_DISMISS_SOUND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x326*/ { "SMSG_GHOSTEE_GONE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x327*/ { "CMSG_GM_UPDATE_TICKET_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x328*/ { "SMSG_GM_TICKET_STATUS_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x329*/ { "MSG_SET_DUNGEON_DIFFICULTY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetDungeonDifficultyOpcode}, - /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMSurveySubmit }, - /*0x32B*/ { "SMSG_UPDATE_INSTANCE_OWNERSHIP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x32C*/ { "CMSG_IGNORE_KNOCKBACK_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x32D*/ { "SMSG_CHAT_PLAYER_AMBIGUOUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x32E*/ { "MSG_DELAY_GHOST_TELEPORT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x32F*/ { "SMSG_SPELLINSTAKILLLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x330*/ { "SMSG_SPELL_UPDATE_CHAIN_TARGETS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x331*/ { "CMSG_CHAT_FILTERED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x332*/ { "SMSG_EXPECTED_SPAM_RECORDS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x333*/ { "SMSG_SPELLSTEALLOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x334*/ { "CMSG_LOTTERY_QUERY_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x335*/ { "SMSG_LOTTERY_QUERY_RESULT_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x336*/ { "CMSG_BUY_LOTTERY_TICKET_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x337*/ { "SMSG_LOTTERY_RESULT_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x338*/ { "SMSG_CHARACTER_PROFILE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x339*/ { "SMSG_CHARACTER_PROFILE_REALM_CONNECTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x33A*/ { "SMSG_DEFENSE_MESSAGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x33B*/ { "SMSG_INSTANCE_DIFFICULTY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x33C*/ { "MSG_GM_RESETINSTANCELIMIT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x33D*/ { "SMSG_MOTD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x33E*/ { "SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x33F*/ { "SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x340*/ { "CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x341*/ { "MSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x342*/ { "MSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x343*/ { "SMSG_MOVE_SET_CAN_FLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x344*/ { "SMSG_MOVE_UNSET_CAN_FLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x345*/ { "CMSG_MOVE_SET_CAN_FLY_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSetCanFlyAckOpcode }, - /*0x346*/ { "CMSG_MOVE_SET_FLY", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x347*/ { "CMSG_SOCKET_GEMS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSocketOpcode }, - /*0x348*/ { "CMSG_ARENA_TEAM_CREATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x349*/ { "SMSG_ARENA_TEAM_COMMAND_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x34A*/ { "MSG_MOVE_UPDATE_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x34B*/ { "CMSG_ARENA_TEAM_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamQueryOpcode }, - /*0x34C*/ { "SMSG_ARENA_TEAM_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x34D*/ { "CMSG_ARENA_TEAM_ROSTER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamRosterOpcode }, - /*0x34E*/ { "SMSG_ARENA_TEAM_ROSTER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x34F*/ { "CMSG_ARENA_TEAM_INVITE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamInviteOpcode }, - /*0x350*/ { "SMSG_ARENA_TEAM_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x351*/ { "CMSG_ARENA_TEAM_ACCEPT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamAcceptOpcode }, - /*0x352*/ { "CMSG_ARENA_TEAM_DECLINE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamDeclineOpcode }, - /*0x353*/ { "CMSG_ARENA_TEAM_LEAVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamLeaveOpcode }, - /*0x354*/ { "CMSG_ARENA_TEAM_REMOVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamRemoveOpcode }, - /*0x355*/ { "CMSG_ARENA_TEAM_DISBAND", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamDisbandOpcode }, - /*0x356*/ { "CMSG_ARENA_TEAM_LEADER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamLeaderOpcode }, - /*0x357*/ { "SMSG_ARENA_TEAM_EVENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x358*/ { "CMSG_BATTLEMASTER_JOIN_ARENA", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlemasterJoinArena }, - /*0x359*/ { "MSG_MOVE_START_ASCEND", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x35A*/ { "MSG_MOVE_STOP_ASCEND", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x35B*/ { "SMSG_ARENA_TEAM_STATS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x35C*/ { "CMSG_LFG_JOIN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgJoinOpcode }, - /*0x35D*/ { "CMSG_LFG_LEAVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgLeaveOpcode }, - /*0x35E*/ { "CMSG_SEARCH_LFG_JOIN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrJoinOpcode }, - /*0x35F*/ { "CMSG_SEARCH_LFG_LEAVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrLeaveOpcode }, - /*0x360*/ { "SMSG_UPDATE_LFG_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x361*/ { "SMSG_LFG_PROPOSAL_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x362*/ { "CMSG_LFG_PROPOSAL_RESULT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgProposalResultOpcode }, - /*0x363*/ { "SMSG_LFG_ROLE_CHECK_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x364*/ { "SMSG_LFG_JOIN_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x365*/ { "SMSG_LFG_QUEUE_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x366*/ { "CMSG_SET_LFG_COMMENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgSetCommentOpcode }, - /*0x367*/ { "SMSG_LFG_UPDATE_PLAYER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x368*/ { "SMSG_LFG_UPDATE_PARTY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x369*/ { "SMSG_LFG_UPDATE_SEARCH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x36A*/ { "CMSG_LFG_SET_ROLES", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgSetRolesOpcode }, - /*0x36B*/ { "CMSG_LFG_SET_NEEDS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x36C*/ { "CMSG_LFG_SET_BOOT_VOTE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgSetBootVoteOpcode }, - /*0x36D*/ { "SMSG_LFG_BOOT_PROPOSAL_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x36E*/ { "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgPlayerLockInfoRequestOpcode}, - /*0x36F*/ { "SMSG_LFG_PLAYER_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x370*/ { "CMSG_LFG_TELEPORT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgTeleportOpcode }, - /*0x371*/ { "CMSG_LFD_PARTY_LOCK_INFO_REQUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgPartyLockInfoRequestOpcode}, - /*0x372*/ { "SMSG_LFG_PARTY_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x373*/ { "SMSG_TITLE_EARNED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x374*/ { "CMSG_SET_TITLE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTitleOpcode }, - /*0x375*/ { "CMSG_CANCEL_MOUNT_AURA", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelMountAuraOpcode }, - /*0x376*/ { "SMSG_ARENA_ERROR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x377*/ { "MSG_INSPECT_ARENA_TEAMS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectArenaTeamsOpcode }, - /*0x378*/ { "SMSG_DEATH_RELEASE_LOC", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x379*/ { "CMSG_CANCEL_TEMP_ENCHANTMENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTempEnchantmentOpcode}, - /*0x37A*/ { "SMSG_FORCED_DEATH_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x37B*/ { "CMSG_CHEAT_SET_HONOR_CURRENCY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x37C*/ { "CMSG_CHEAT_SET_ARENA_CURRENCY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x37D*/ { "MSG_MOVE_SET_FLIGHT_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x37E*/ { "MSG_MOVE_SET_FLIGHT_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x37F*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x380*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x381*/ { "SMSG_FORCE_FLIGHT_SPEED_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x382*/ { "CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck }, - /*0x383*/ { "SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x384*/ { "CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck }, - /*0x385*/ { "SMSG_SPLINE_SET_FLIGHT_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x386*/ { "SMSG_SPLINE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x387*/ { "CMSG_MAELSTROM_INVALIDATE_CACHE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x388*/ { "SMSG_FLIGHT_SPLINE_SYNC", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x389*/ { "CMSG_SET_TAXI_BENCHMARK_MODE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTaxiBenchmarkOpcode }, - /*0x38A*/ { "SMSG_JOINED_BATTLEGROUND_QUEUE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x38B*/ { "SMSG_REALM_SPLIT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x38C*/ { "CMSG_REALM_SPLIT", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleRealmSplitOpcode }, - /*0x38D*/ { "CMSG_MOVE_CHNG_TRANSPORT", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x38E*/ { "MSG_PARTY_ASSIGNMENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyAssignmentOpcode }, - /*0x38F*/ { "SMSG_OFFER_PETITION_ERROR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x390*/ { "SMSG_TIME_SYNC_REQ", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x391*/ { "CMSG_TIME_SYNC_RESP", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleTimeSyncResp }, - /*0x392*/ { "CMSG_SEND_LOCAL_EVENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x393*/ { "CMSG_SEND_GENERAL_TRIGGER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x394*/ { "CMSG_SEND_COMBAT_TRIGGER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x395*/ { "CMSG_MAELSTROM_GM_SENT_MAIL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x396*/ { "SMSG_RESET_FAILED_NOTIFY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x397*/ { "SMSG_REAL_GROUP_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x398*/ { "SMSG_LFG_DISABLED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x399*/ { "CMSG_ACTIVE_PVP_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x39A*/ { "CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x39B*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x39C*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x39D*/ { "SMSG_UPDATE_COMBO_POINTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x39E*/ { "SMSG_VOICE_SESSION_ROSTER_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x39F*/ { "SMSG_VOICE_SESSION_LEAVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3A0*/ { "SMSG_VOICE_SESSION_ADJUST_PRIORITY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3A1*/ { "CMSG_VOICE_SET_TALKER_MUTED_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3A2*/ { "SMSG_VOICE_SET_TALKER_MUTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3A3*/ { "SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3A4*/ { "SMSG_SET_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3A5*/ { "SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3A6*/ { "SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3A7*/ { "MSG_MOVE_START_DESCEND", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes }, - /*0x3A8*/ { "CMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3A9*/ { "SMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3AA*/ { "SMSG_SPELL_CHANCE_PROC_LOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3AB*/ { "CMSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3AC*/ { "SMSG_DISMOUNT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3AD*/ { "MSG_MOVE_UPDATE_CAN_FLY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3AE*/ { "MSG_RAID_READY_CHECK_CONFIRM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3AF*/ { "CMSG_VOICE_SESSION_ENABLE", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleVoiceSessionEnableOpcode }, - /*0x3B0*/ { "SMSG_VOICE_SESSION_ENABLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3B1*/ { "SMSG_VOICE_PARENTAL_CONTROLS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3B2*/ { "CMSG_GM_WHISPER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3B3*/ { "SMSG_GM_MESSAGECHAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3B4*/ { "MSG_GM_GEARRATING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3B5*/ { "CMSG_COMMENTATOR_ENABLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3B6*/ { "SMSG_COMMENTATOR_STATE_CHANGED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3B7*/ { "CMSG_COMMENTATOR_GET_MAP_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3B8*/ { "SMSG_COMMENTATOR_MAP_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3B9*/ { "CMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3BA*/ { "SMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3BB*/ { "SMSG_COMMENTATOR_PLAYER_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3BC*/ { "CMSG_COMMENTATOR_ENTER_INSTANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3BD*/ { "CMSG_COMMENTATOR_EXIT_INSTANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3BE*/ { "CMSG_COMMENTATOR_INSTANCE_COMMAND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3BF*/ { "SMSG_CLEAR_TARGET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3C0*/ { "CMSG_BOT_DETECTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3C1*/ { "SMSG_CROSSED_INEBRIATION_THRESHOLD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3C2*/ { "CMSG_CHEAT_PLAYER_LOGIN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3C3*/ { "CMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3C4*/ { "SMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3C5*/ { "SMSG_KICK_REASON", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3C6*/ { "MSG_RAID_READY_CHECK_FINISHED", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidReadyCheckFinishedOpcode}, - /*0x3C7*/ { "CMSG_COMPLAIN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleComplainOpcode }, - /*0x3C8*/ { "SMSG_COMPLAIN_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3C9*/ { "SMSG_FEATURE_SYSTEM_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3CA*/ { "CMSG_GM_SHOW_COMPLAINTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3CB*/ { "CMSG_GM_UNSQUELCH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3CC*/ { "CMSG_CHANNEL_SILENCE_VOICE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3CD*/ { "CMSG_CHANNEL_SILENCE_ALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3CE*/ { "CMSG_CHANNEL_UNSILENCE_VOICE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3CF*/ { "CMSG_CHANNEL_UNSILENCE_ALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3D0*/ { "CMSG_TARGET_CAST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3D1*/ { "CMSG_TARGET_SCRIPT_CAST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3D2*/ { "CMSG_CHANNEL_DISPLAY_LIST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelDisplayListQuery }, - /*0x3D3*/ { "CMSG_SET_ACTIVE_VOICE_CHANNEL", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveVoiceChannel }, - /*0x3D4*/ { "CMSG_GET_CHANNEL_MEMBER_COUNT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetChannelMemberCount }, - /*0x3D5*/ { "SMSG_CHANNEL_MEMBER_COUNT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3D6*/ { "CMSG_CHANNEL_VOICE_ON", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelVoiceOnOpcode }, - /*0x3D7*/ { "CMSG_CHANNEL_VOICE_OFF", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3D8*/ { "CMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3D9*/ { "SMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3DA*/ { "SMSG_AVAILABLE_VOICE_CHANNEL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3DB*/ { "CMSG_ADD_VOICE_IGNORE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3DC*/ { "CMSG_DEL_VOICE_IGNORE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3DD*/ { "CMSG_PARTY_SILENCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3DE*/ { "CMSG_PARTY_UNSILENCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3DF*/ { "MSG_NOTIFY_PARTY_SQUELCH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3E0*/ { "SMSG_COMSAT_RECONNECT_TRY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3E1*/ { "SMSG_COMSAT_DISCONNECT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3E2*/ { "SMSG_COMSAT_CONNECT_FAIL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3E3*/ { "SMSG_VOICE_CHAT_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3E4*/ { "CMSG_REPORT_PVP_AFK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReportPvPAFK }, - /*0x3E5*/ { "SMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3E6*/ { "CMSG_GUILD_BANKER_ACTIVATE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankerActivate }, - /*0x3E7*/ { "CMSG_GUILD_BANK_QUERY_TAB", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankQueryTab }, - /*0x3E8*/ { "SMSG_GUILD_BANK_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3E9*/ { "CMSG_GUILD_BANK_SWAP_ITEMS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankSwapItems }, - /*0x3EA*/ { "CMSG_GUILD_BANK_BUY_TAB", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankBuyTab }, - /*0x3EB*/ { "CMSG_GUILD_BANK_UPDATE_TAB", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankUpdateTab }, - /*0x3EC*/ { "CMSG_GUILD_BANK_DEPOSIT_MONEY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankDepositMoney }, - /*0x3ED*/ { "CMSG_GUILD_BANK_WITHDRAW_MONEY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankWithdrawMoney }, - /*0x3EE*/ { "MSG_GUILD_BANK_LOG_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankLogQuery }, - /*0x3EF*/ { "CMSG_SET_CHANNEL_WATCH", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetChannelWatch }, - /*0x3F0*/ { "SMSG_USERLIST_ADD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3F1*/ { "SMSG_USERLIST_REMOVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3F2*/ { "SMSG_USERLIST_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3F3*/ { "CMSG_CLEAR_CHANNEL_WATCH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3F4*/ { "SMSG_INSPECT_TALENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3F5*/ { "SMSG_GOGOGO_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3F6*/ { "SMSG_ECHO_PARTY_SQUELCH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3F7*/ { "CMSG_SET_TITLE_SUFFIX", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3F8*/ { "CMSG_SPELLCLICK", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSpellClick }, - /*0x3F9*/ { "SMSG_LOOT_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3FA*/ { "CMSG_GM_CHARACTER_RESTORE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3FB*/ { "CMSG_GM_CHARACTER_SAVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x3FC*/ { "SMSG_VOICESESSION_FULL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x3FD*/ { "MSG_GUILD_PERMISSIONS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildPermissions }, - /*0x3FE*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankMoneyWithdrawn }, - /*0x3FF*/ { "MSG_GUILD_EVENT_LOG_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildEventLogQueryOpcode }, - /*0x400*/ { "CMSG_MAELSTROM_RENAME_GUILD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMirrorImageDataRequest }, - /*0x402*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x403*/ { "SMSG_FORCE_DISPLAY_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x404*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x405*/ { "CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x406*/ { "SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x407*/ { "CMSG_KEEP_ALIVE", STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess }, - /*0x408*/ { "SMSG_RAID_READY_CHECK_ERROR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x409*/ { "CMSG_OPT_OUT_OF_LOOT", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleOptOutOfLootOpcode }, - /*0x40A*/ { "MSG_QUERY_GUILD_BANK_TEXT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryGuildBankTabText }, - /*0x40B*/ { "CMSG_SET_GUILD_BANK_TEXT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetGuildBankTabText }, - /*0x40C*/ { "CMSG_SET_GRANTABLE_LEVELS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x40D*/ { "CMSG_GRANT_LEVEL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGrantLevel }, - /*0x40E*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x40F*/ { "MSG_GM_CHANGE_ARENA_RATING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x410*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleChannelDeclineInvite }, - /*0x411*/ { "SMSG_GROUPACTION_THROTTLED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x412*/ { "SMSG_OVERRIDE_LIGHT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x413*/ { "SMSG_TOTEM_CREATED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x414*/ { "CMSG_TOTEM_DESTROYED", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTotemDestroyed }, - /*0x415*/ { "CMSG_EXPIRE_RAID_INSTANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x416*/ { "CMSG_NO_SPELL_VARIANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x417*/ { "CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverStatusMultipleQuery}, - /*0x418*/ { "SMSG_QUESTGIVER_STATUS_MULTIPLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x419*/ { "CMSG_SET_PLAYER_DECLINED_NAMES", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPlayerDeclinedNames }, - /*0x41A*/ { "SMSG_SET_PLAYER_DECLINED_NAMES_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x41B*/ { "CMSG_QUERY_SERVER_BUCK_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x41C*/ { "CMSG_CLEAR_SERVER_BUCK_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x41D*/ { "SMSG_SERVER_BUCK_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x41E*/ { "SMSG_SEND_UNLEARN_SPELLS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x41F*/ { "SMSG_PROPOSE_LEVEL_GRANT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x420*/ { "CMSG_ACCEPT_LEVEL_GRANT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptGrantLevel }, - /*0x421*/ { "SMSG_REFER_A_FRIEND_FAILURE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x422*/ { "SMSG_SPLINE_MOVE_SET_FLYING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x423*/ { "SMSG_SPLINE_MOVE_UNSET_FLYING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x424*/ { "SMSG_SUMMON_CANCEL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x425*/ { "CMSG_CHANGE_PERSONAL_ARENA_RATING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x426*/ { "CMSG_ALTER_APPEARANCE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAlterAppearance }, - /*0x427*/ { "SMSG_ENABLE_BARBER_SHOP", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x428*/ { "SMSG_BARBER_SHOP_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x429*/ { "CMSG_CALENDAR_GET_CALENDAR", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGetCalendar }, - /*0x42A*/ { "CMSG_CALENDAR_GET_EVENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGetEvent }, - /*0x42B*/ { "CMSG_CALENDAR_GUILD_FILTER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGuildFilter }, - /*0x42C*/ { "CMSG_CALENDAR_ARENA_TEAM", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarArenaTeam }, - /*0x42D*/ { "CMSG_CALENDAR_ADD_EVENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarAddEvent }, - /*0x42E*/ { "CMSG_CALENDAR_UPDATE_EVENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarUpdateEvent }, - /*0x42F*/ { "CMSG_CALENDAR_REMOVE_EVENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarRemoveEvent }, - /*0x430*/ { "CMSG_CALENDAR_COPY_EVENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarCopyEvent }, - /*0x431*/ { "CMSG_CALENDAR_EVENT_INVITE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventInvite }, - /*0x432*/ { "CMSG_CALENDAR_EVENT_RSVP", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventRsvp }, - /*0x433*/ { "CMSG_CALENDAR_EVENT_REMOVE_INVITE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventRemoveInvite }, - /*0x434*/ { "CMSG_CALENDAR_EVENT_STATUS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventStatus }, - /*0x435*/ { "CMSG_CALENDAR_EVENT_MODERATOR_STATUS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventModeratorStatus}, - /*0x436*/ { "SMSG_CALENDAR_SEND_CALENDAR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x437*/ { "SMSG_CALENDAR_SEND_EVENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x438*/ { "SMSG_CALENDAR_FILTER_GUILD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x439*/ { "SMSG_CALENDAR_ARENA_TEAM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x43A*/ { "SMSG_CALENDAR_EVENT_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x43B*/ { "SMSG_CALENDAR_EVENT_INVITE_REMOVED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x43C*/ { "SMSG_CALENDAR_EVENT_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x43D*/ { "SMSG_CALENDAR_COMMAND_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x43E*/ { "SMSG_CALENDAR_RAID_LOCKOUT_ADDED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x43F*/ { "SMSG_CALENDAR_RAID_LOCKOUT_REMOVED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x440*/ { "SMSG_CALENDAR_EVENT_INVITE_ALERT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x441*/ { "SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x442*/ { "SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x443*/ { "SMSG_CALENDAR_EVENT_REMOVED_ALERT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x444*/ { "SMSG_CALENDAR_EVENT_UPDATED_ALERT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x445*/ { "SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x446*/ { "CMSG_CALENDAR_COMPLAIN", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarComplain }, - /*0x447*/ { "CMSG_CALENDAR_GET_NUM_PENDING", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGetNumPending }, - /*0x448*/ { "SMSG_CALENDAR_SEND_NUM_PENDING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x449*/ { "CMSG_SAVE_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x44A*/ { "SMSG_NOTIFY_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x44B*/ { "CMSG_PLAY_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x44C*/ { "SMSG_PLAY_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x44D*/ { "CMSG_LOAD_DANCES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x44E*/ { "CMSG_STOP_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x44F*/ { "SMSG_STOP_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x450*/ { "CMSG_SYNC_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x451*/ { "CMSG_DANCE_QUERY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x452*/ { "SMSG_DANCE_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x453*/ { "SMSG_INVALIDATE_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x454*/ { "CMSG_DELETE_DANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x455*/ { "SMSG_LEARNED_DANCE_MOVES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x456*/ { "CMSG_LEARN_DANCE_MOVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x457*/ { "CMSG_UNLEARN_DANCE_MOVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x458*/ { "CMSG_SET_RUNE_COUNT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x459*/ { "CMSG_SET_RUNE_COOLDOWN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x45A*/ { "MSG_MOVE_SET_PITCH_RATE_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x45B*/ { "MSG_MOVE_SET_PITCH_RATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x45C*/ { "SMSG_FORCE_PITCH_RATE_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x45D*/ { "CMSG_FORCE_PITCH_RATE_CHANGE_ACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x45E*/ { "SMSG_SPLINE_SET_PITCH_RATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x45F*/ { "CMSG_CALENDAR_EVENT_INVITE_NOTES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x460*/ { "SMSG_CALENDAR_EVENT_INVITE_NOTES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x461*/ { "SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x462*/ { "CMSG_UPDATE_MISSILE_TRAJECTORY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateMissileTrajectory }, - /*0x463*/ { "SMSG_UPDATE_ACCOUNT_DATA_COMPLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x464*/ { "SMSG_TRIGGER_MOVIE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x465*/ { "CMSG_COMPLETE_MOVIE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x466*/ { "CMSG_SET_GLYPH_SLOT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x467*/ { "CMSG_SET_GLYPH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x468*/ { "SMSG_ACHIEVEMENT_EARNED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x469*/ { "SMSG_DYNAMIC_DROP_ROLL_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x46A*/ { "SMSG_CRITERIA_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x46B*/ { "CMSG_QUERY_INSPECT_ACHIEVEMENTS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryInspectAchievements }, - /*0x46C*/ { "SMSG_RESPOND_INSPECT_ACHIEVEMENTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x46D*/ { "CMSG_DISMISS_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDismissControlledVehicle }, - /*0x46E*/ { "CMSG_COMPLETE_ACHIEVEMENT_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x46F*/ { "SMSG_QUESTUPDATE_ADD_PVP_KILL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x470*/ { "CMSG_SET_CRITERIA_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x471*/ { "SMSG_CALENDAR_RAID_LOCKOUT_UPDATED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x472*/ { "CMSG_UNITANIMTIER_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x473*/ { "CMSG_CHAR_CUSTOMIZE", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharCustomize }, - /*0x474*/ { "SMSG_CHAR_CUSTOMIZE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x475*/ { "SMSG_PET_RENAMEABLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x476*/ { "CMSG_REQUEST_VEHICLE_EXIT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestVehicleExit }, - /*0x477*/ { "CMSG_REQUEST_VEHICLE_PREV_SEAT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle}, - /*0x478*/ { "CMSG_REQUEST_VEHICLE_NEXT_SEAT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle}, - /*0x479*/ { "CMSG_REQUEST_VEHICLE_SWITCH_SEAT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle}, - /*0x47A*/ { "CMSG_PET_LEARN_TALENT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetLearnTalent }, - /*0x47B*/ { "CMSG_PET_UNLEARN_TALENTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x47C*/ { "SMSG_SET_PHASE_SHIFT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x47D*/ { "SMSG_ALL_ACHIEVEMENT_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x47E*/ { "CMSG_FORCE_SAY_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x47F*/ { "SMSG_HEALTH_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x480*/ { "SMSG_POWER_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x481*/ { "CMSG_GAMEOBJ_REPORT_USE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGameobjectReportUse }, - /*0x482*/ { "SMSG_HIGHEST_THREAT_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x483*/ { "SMSG_THREAT_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x484*/ { "SMSG_THREAT_REMOVE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x485*/ { "SMSG_THREAT_CLEAR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x486*/ { "SMSG_CONVERT_RUNE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x487*/ { "SMSG_RESYNC_RUNES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x488*/ { "SMSG_ADD_RUNE_POWER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x489*/ { "CMSG_START_QUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x48A*/ { "CMSG_REMOVE_GLYPH", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRemoveGlyph }, - /*0x48B*/ { "CMSG_DUMP_OBJECTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x48C*/ { "SMSG_DUMP_OBJECTS_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x48D*/ { "CMSG_DISMISS_CRITTER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDismissCritter }, - /*0x48E*/ { "SMSG_NOTIFY_DEST_LOC_SPELL_CAST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x48F*/ { "CMSG_AUCTION_LIST_PENDING_SALES", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListPendingSales }, - /*0x490*/ { "SMSG_AUCTION_LIST_PENDING_SALES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x491*/ { "SMSG_MODIFY_COOLDOWN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x492*/ { "SMSG_PET_UPDATE_COMBO_POINTS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x493*/ { "CMSG_ENABLETAXI", STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes }, - /*0x494*/ { "SMSG_PRE_RESURRECT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x495*/ { "SMSG_AURA_UPDATE_ALL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x496*/ { "SMSG_AURA_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x497*/ { "CMSG_FLOOD_GRACE_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x498*/ { "SMSG_SERVER_FIRST_ACHIEVEMENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x499*/ { "SMSG_PET_LEARNED_SPELL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x49A*/ { "SMSG_PET_REMOVED_SPELL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x49B*/ { "CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle}, - /*0x49C*/ { "CMSG_HEARTH_AND_RESURRECT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleHearthAndResurrect }, - /*0x49D*/ { "SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x49E*/ { "SMSG_CRITERIA_DELETED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x49F*/ { "SMSG_ACHIEVEMENT_DELETED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4A0*/ { "CMSG_SERVER_INFO_QUERY", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4A1*/ { "SMSG_SERVER_INFO_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4A2*/ { "CMSG_CHECK_LOGIN_CRITERIA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4A3*/ { "SMSG_SERVER_BUCK_DATA_START", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4A4*/ { "CMSG_SET_BREATH", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4A5*/ { "CMSG_QUERY_VEHICLE_STATUS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4A6*/ { "SMSG_BATTLEGROUND_INFO_THROTTLED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4A7*/ { "SMSG_PLAYER_VEHICLE_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4A8*/ { "CMSG_PLAYER_VEHICLE_ENTER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEnterPlayerVehicle }, - /*0x4A9*/ { "CMSG_CONTROLLER_EJECT_PASSENGER", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEjectPassenger }, - /*0x4AA*/ { "SMSG_PET_GUIDS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4AB*/ { "SMSG_CLIENTCACHE_VERSION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4AC*/ { "CMSG_CHANGE_GDF_ARENA_RATING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4AD*/ { "CMSG_SET_ARENA_TEAM_RATING_BY_INDEX", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4AE*/ { "CMSG_SET_ARENA_TEAM_WEEKLY_GAMES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4AF*/ { "CMSG_SET_ARENA_TEAM_SEASON_GAMES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4B0*/ { "CMSG_SET_ARENA_MEMBER_WEEKLY_GAMES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4B1*/ { "CMSG_SET_ARENA_MEMBER_SEASON_GAMES", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4B2*/ { "SMSG_ITEM_REFUND_INFO_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4B3*/ { "CMSG_ITEM_REFUND_INFO", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleItemRefundInfoRequest }, - /*0x4B4*/ { "CMSG_ITEM_REFUND", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleItemRefund }, - /*0x4B5*/ { "SMSG_ITEM_REFUND_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4B6*/ { "CMSG_CORPSE_MAP_POSITION_QUERY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCorpseMapPositionQuery }, - /*0x4B7*/ { "SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4B8*/ { "CMSG_UNUSED5", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL }, - /*0x4B9*/ { "CMSG_UNUSED6", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4BA*/ { "CMSG_CALENDAR_EVENT_SIGNUP", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventSignup }, - /*0x4BB*/ { "SMSG_CALENDAR_CLEAR_PENDING_ACTION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4BC*/ { "SMSG_EQUIPMENT_SET_LIST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4BD*/ { "CMSG_EQUIPMENT_SET_SAVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetSave }, - /*0x4BE*/ { "CMSG_UPDATE_PROJECTILE_POSITION", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateProjectilePosition }, - /*0x4BF*/ { "SMSG_SET_PROJECTILE_POSITION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4C0*/ { "SMSG_TALENTS_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4C1*/ { "CMSG_LEARN_PREVIEW_TALENTS", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalents }, - /*0x4C2*/ { "CMSG_LEARN_PREVIEW_TALENTS_PET", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalentsPet }, - /*0x4C3*/ { "CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4C4*/ { "CMSG_GM_GRANT_ACHIEVEMENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4C5*/ { "CMSG_GM_REMOVE_ACHIEVEMENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4C6*/ { "CMSG_GM_SET_CRITERIA_FOR_PLAYER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4C7*/ { "SMSG_ARENA_UNIT_DESTROYED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4C8*/ { "SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4C9*/ { "CMSG_PROFILEDATA_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4CA*/ { "SMSG_PROFILEDATA_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4CB*/ { "CMSG_START_BATTLEFIELD_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4CC*/ { "CMSG_END_BATTLEFIELD_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4CD*/ { "SMSG_MULTIPLE_PACKETS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4CE*/ { "SMSG_MOVE_GRAVITY_DISABLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4CF*/ { "CMSG_MOVE_GRAVITY_DISABLE_ACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4D0*/ { "SMSG_MOVE_GRAVITY_ENABLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4D1*/ { "CMSG_MOVE_GRAVITY_ENABLE_ACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4D2*/ { "MSG_MOVE_GRAVITY_CHNG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4D3*/ { "SMSG_SPLINE_MOVE_GRAVITY_DISABLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4D4*/ { "SMSG_SPLINE_MOVE_GRAVITY_ENABLE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4D5*/ { "CMSG_EQUIPMENT_SET_USE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetUse }, - /*0x4D6*/ { "SMSG_EQUIPMENT_SET_USE_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4D7*/ { "CMSG_FORCE_ANIM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4D8*/ { "SMSG_FORCE_ANIM", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4D9*/ { "CMSG_CHAR_FACTION_CHANGE", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharFactionOrRaceChange }, - /*0x4DA*/ { "SMSG_CHAR_FACTION_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4DB*/ { "CMSG_PVP_QUEUE_STATS_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4DC*/ { "SMSG_PVP_QUEUE_STATS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4DD*/ { "CMSG_SET_PAID_SERVICE_CHEAT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4DE*/ { "SMSG_BATTLEFIELD_MGR_ENTRY_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4DF*/ { "CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfEntryInviteResponse }, - /*0x4E0*/ { "SMSG_BATTLEFIELD_MGR_ENTERED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4E1*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4E2*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfQueueInviteResponse }, - /*0x4E3*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4E4*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4E5*/ { "SMSG_BATTLEFIELD_MGR_EJECT_PENDING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4E6*/ { "SMSG_BATTLEFIELD_MGR_EJECTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4E7*/ { "CMSG_BATTLEFIELD_MGR_EXIT_REQUEST", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfExitRequest }, - /*0x4E8*/ { "SMSG_BATTLEFIELD_MGR_STATE_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4E9*/ { "CMSG_BATTLEFIELD_MANAGER_ADVANCE_STATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4EA*/ { "CMSG_BATTLEFIELD_MANAGER_SET_NEXT_TRANSITION_TIME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4EB*/ { "MSG_SET_RAID_DIFFICULTY", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetRaidDifficultyOpcode }, - /*0x4EC*/ { "CMSG_TOGGLE_XP_GAIN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4ED*/ { "SMSG_TOGGLE_XP_GAIN", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4EE*/ { "SMSG_GMRESPONSE_DB_ERROR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4EF*/ { "SMSG_GMRESPONSE_RECEIVED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4F0*/ { "CMSG_GMRESPONSE_RESOLVE", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMResponseResolve }, - /*0x4F1*/ { "SMSG_GMRESPONSE_STATUS_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4F2*/ { "SMSG_GMRESPONSE_CREATE_TICKET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4F3*/ { "CMSG_GMRESPONSE_CREATE_TICKET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4F4*/ { "CMSG_SERVERINFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4F5*/ { "SMSG_SERVERINFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4F6*/ { "CMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleWorldStateUITimerUpdate }, - /*0x4F7*/ { "SMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4F8*/ { "CMSG_CHAR_RACE_CHANGE", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharFactionOrRaceChange }, - /*0x4F9*/ { "MSG_VIEW_PHASE_SHIFT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4FA*/ { "SMSG_TALENTS_INVOLUNTARILY_RESET", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4FB*/ { "CMSG_DEBUG_SERVER_GEO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4FC*/ { "SMSG_DEBUG_SERVER_GEO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4FD*/ { "SMSG_LOOT_SLOT_CHANGED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4FE*/ { "UMSG_UPDATE_GROUP_INFO", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x4FF*/ { "CMSG_READY_FOR_ACCOUNT_DATA_TIMES", STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleReadyForAccountDataTimes }, - /*0x500*/ { "CMSG_QUERY_QUESTS_COMPLETED", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryQuestsCompleted }, - /*0x501*/ { "SMSG_QUERY_QUESTS_COMPLETED_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x502*/ { "CMSG_GM_REPORT_LAG", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReportLag }, - /*0x503*/ { "CMSG_AFK_MONITOR_INFO_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x504*/ { "SMSG_AFK_MONITOR_INFO_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x505*/ { "CMSG_AFK_MONITOR_INFO_CLEAR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x506*/ { "SMSG_CORPSE_IS_NOT_IN_INSTANCE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x507*/ { "CMSG_GM_NUKE_CHARACTER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x508*/ { "CMSG_SET_ALLOW_LOW_LEVEL_RAID1", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x509*/ { "CMSG_SET_ALLOW_LOW_LEVEL_RAID2", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x50A*/ { "SMSG_CAMERA_SHAKE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x50B*/ { "SMSG_SOCKET_GEMS_RESULT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x50C*/ { "CMSG_SET_CHARACTER_MODEL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x50D*/ { "SMSG_REDIRECT_CLIENT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x50E*/ { "CMSG_REDIRECTION_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x50F*/ { "SMSG_SUSPEND_COMMS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x510*/ { "CMSG_SUSPEND_COMMS_ACK", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x511*/ { "SMSG_FORCE_SEND_QUEUED_PACKETS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x512*/ { "CMSG_REDIRECTION_AUTH_PROOF", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x513*/ { "CMSG_DROP_NEW_CONNECTION", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x514*/ { "SMSG_SEND_ALL_COMBAT_LOG", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x515*/ { "SMSG_OPEN_LFG_DUNGEON_FINDER", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x516*/ { "SMSG_MOVE_SET_COLLISION_HGT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x517*/ { "CMSG_MOVE_SET_COLLISION_HGT_ACK", STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x518*/ { "MSG_MOVE_SET_COLLISION_HGT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x519*/ { "CMSG_CLEAR_RANDOM_BG_WIN_TIME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x51A*/ { "CMSG_CLEAR_HOLIDAY_BG_WIN_TIME", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x51B*/ { "CMSG_COMMENTATOR_SKIRMISH_QUEUE_COMMAND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x51C*/ { "SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x51D*/ { "SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x51E*/ { "SMSG_COMPRESSED_UNKNOWN_1310", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, +#define DEFINE_OPCODE_HANDLER(opcode, status, processing, handler) \ + ValidateAndSetOpcode<(opcode < NUM_OPCODE_HANDLERS), (opcode != 0)>(opcode, #opcode, status, processing, handler); + + DEFINE_OPCODE_HANDLER(CMSG_ACCEPT_LEVEL_GRANT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptGrantLevel ); + DEFINE_OPCODE_HANDLER(CMSG_ACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptTradeOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ACTIVATETAXI, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleActivateTaxiOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ACTIVATETAXIEXPRESS, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleActivateTaxiExpressOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ADDON_REGISTERED_PREFIXES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonRegisteredPrefixesOpcode); + DEFINE_OPCODE_HANDLER(CMSG_ADD_FRIEND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddFriendOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ADD_IGNORE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddIgnoreOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ADD_VOICE_IGNORE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_ALTER_APPEARANCE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAlterAppearance ); + DEFINE_OPCODE_HANDLER(CMSG_AREATRIGGER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaTriggerOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AREA_SPIRIT_HEALER_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaSpiritHealerQueryOpcode); + DEFINE_OPCODE_HANDLER(CMSG_AREA_SPIRIT_HEALER_QUEUE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaSpiritHealerQueueOpcode); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_ACCEPT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamAcceptOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_CREATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamCreateOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_DECLINE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamDeclineOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_DISBAND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamDisbandOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamInviteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_LEADER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamLeaderOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_LEAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamLeaveOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_REMOVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamRemoveOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ARENA_TEAM_ROSTER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamRosterOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ATTACKSTOP, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleAttackStopOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ATTACKSWING, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleAttackSwingOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUCTION_LIST_BIDDER_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListBidderItems ); + DEFINE_OPCODE_HANDLER(CMSG_AUCTION_LIST_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListItems ); + DEFINE_OPCODE_HANDLER(CMSG_AUCTION_LIST_OWNER_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListOwnerItems ); + DEFINE_OPCODE_HANDLER(CMSG_AUCTION_LIST_PENDING_SALES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListPendingSales ); + DEFINE_OPCODE_HANDLER(CMSG_AUCTION_PLACE_BID, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionPlaceBid ); + DEFINE_OPCODE_HANDLER(CMSG_AUCTION_REMOVE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionRemoveItem ); + DEFINE_OPCODE_HANDLER(CMSG_AUCTION_SELL_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionSellItem ); + DEFINE_OPCODE_HANDLER(CMSG_AUTH_SESSION, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOBANK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoBankItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOEQUIP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOEQUIP_ITEM_SLOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemSlotOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_BAG_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBagItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_BANK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBankItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_LOOT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutostoreLootItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTO_DECLINE_GUILD_INVITES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoDeclineGuildInvites ); + DEFINE_OPCODE_HANDLER(CMSG_BANKER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBankerActivateOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_LEAVE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBattlefieldLeaveOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlefieldListOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfEntryInviteResponse ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_MGR_EXIT_REQUEST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfExitRequest ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfQueueInviteResponse ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_PORT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattleFieldPortOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_STATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlefieldStatusOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEGROUND_PLAYER_POSITIONS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBattlegroundPlayerPositionsOpcode); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEMASTER_JOIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlemasterJoinOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEMASTER_JOIN_ARENA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlemasterJoinArena ); + DEFINE_OPCODE_HANDLER(CMSG_BATTLEMASTER_JOIN_RATED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_BEGIN_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBeginTradeOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BINDER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBinderActivateOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BUG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBugOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BUSY_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBusyTradeOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BUYBACK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuybackItem ); + DEFINE_OPCODE_HANDLER(CMSG_BUY_BANK_SLOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyBankSlotOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_BUY_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_ADD_EVENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarAddEvent ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_ARENA_TEAM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarArenaTeam ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_COMPLAIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarComplain ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_COPY_EVENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarCopyEvent ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_EVENT_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventInvite ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_EVENT_MODERATOR_STATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventModeratorStatus); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_EVENT_REMOVE_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventRemoveInvite ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_EVENT_RSVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventRsvp ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_EVENT_SIGNUP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventSignup ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_EVENT_STATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarEventStatus ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_GET_CALENDAR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGetCalendar ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_GET_EVENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGetEvent ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_GET_NUM_PENDING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGetNumPending ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_GUILD_FILTER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarGuildFilter ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_REMOVE_EVENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarRemoveEvent ); + DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_UPDATE_EVENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarUpdateEvent ); + DEFINE_OPCODE_HANDLER(CMSG_CANCEL_AURA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelAuraOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CANCEL_AUTO_REPEAT_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelAutoRepeatSpellOpcode); + DEFINE_OPCODE_HANDLER(CMSG_CANCEL_CAST, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleCancelCastOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CANCEL_CHANNELLING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelChanneling ); + DEFINE_OPCODE_HANDLER(CMSG_CANCEL_MOUNT_AURA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelMountAuraOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CANCEL_QUEUED_SPELL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CANCEL_TEMP_ENCHANTMENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTempEnchantmentOpcode); + DEFINE_OPCODE_HANDLER(CMSG_CANCEL_TRADE, STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTradeOpcode); + DEFINE_OPCODE_HANDLER(CMSG_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleCastSpellOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CHANGEPLAYER_DIFFICULTY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_ANNOUNCEMENTS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelAnnouncements ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_BAN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelBan ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_DISPLAY_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelDisplayListQuery ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelInvite ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_KICK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelKick ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelList ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_MODERATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_MODERATOR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelModerator ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_MUTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelMute ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_OWNER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelOwner ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_PASSWORD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelPassword ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_ROSTER_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_SET_OWNER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelSetOwner ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_SILENCE_ALL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_SILENCE_VOICE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_UNBAN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelUnban ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_UNMODERATOR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelUnmoderator ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_UNMUTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelUnmute ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_UNSILENCE_ALL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_UNSILENCE_VOICE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_VOICE_OFF, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelVoiceOnOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CHANNEL_VOICE_ON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChannelVoiceOnOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CHAR_CREATE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharCreateOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CHAR_CUSTOMIZE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharCustomize ); + DEFINE_OPCODE_HANDLER(CMSG_CHAR_DELETE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharDeleteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CHAR_ENUM, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharEnumOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CHAR_FACTION_CHANGE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharFactionOrRaceChange ); + DEFINE_OPCODE_HANDLER(CMSG_CHAR_RACE_CHANGE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharFactionOrRaceChange ); + DEFINE_OPCODE_HANDLER(CMSG_CHAR_RENAME, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharRenameOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CHAT_FILTERED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CHAT_IGNORED, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChatIgnoredOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CLEAR_CHANNEL_WATCH, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CLEAR_RAID_MARKER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CLEAR_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleClearTradeItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_ENABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_ENTER_INSTANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_EXIT_INSTANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_GET_MAP_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_GET_PARTY_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_GET_PLAYER_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_INSTANCE_COMMAND, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_SKIRMISH_QUEUE_COMMAND, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMMENTATOR_START_WARGAME, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_COMPLAIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleComplainOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_COMPLETE_CINEMATIC, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCompleteCinematic ); + DEFINE_OPCODE_HANDLER(CMSG_COMPLETE_MOVIE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CONNECT_TO_FAILED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_CONTACT_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleContactListOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_CORPSE_MAP_POSITION_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCorpseMapPositionQuery ); + DEFINE_OPCODE_HANDLER(CMSG_CREATURE_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleCreatureQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_DANCE_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_DEL_FRIEND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDelFriendOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_DEL_IGNORE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDelIgnoreOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_DEL_VOICE_IGNORE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_DESTROY_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDestroyItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_DISMISS_CONTROLLED_VEHICLE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDismissControlledVehicle ); + DEFINE_OPCODE_HANDLER(CMSG_DISMISS_CRITTER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDismissCritter ); + DEFINE_OPCODE_HANDLER(CMSG_DUEL_ACCEPTED, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDuelAcceptedOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_DUEL_CANCELLED, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleDuelCancelledOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_EJECT_PASSENGER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_EMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEmoteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ENABLETAXI, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes ); + DEFINE_OPCODE_HANDLER(CMSG_ENABLE_NAGLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess ); + DEFINE_OPCODE_HANDLER(CMSG_EQUIPMENT_SET_DELETE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetDelete ); + DEFINE_OPCODE_HANDLER(CMSG_EQUIPMENT_SET_SAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetSave ); + DEFINE_OPCODE_HANDLER(CMSG_EQUIPMENT_SET_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetUse ); + DEFINE_OPCODE_HANDLER(CMSG_FAR_SIGHT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleFarSightOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_FORCE_MOVE_ROOT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveRootAck ); + DEFINE_OPCODE_HANDLER(CMSG_FORCE_MOVE_UNROOT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveUnRootAck ); + DEFINE_OPCODE_HANDLER(CMSG_GAMEOBJECT_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGameObjectQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GAMEOBJ_REPORT_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGameobjectReportUse ); + DEFINE_OPCODE_HANDLER(CMSG_GAMEOBJ_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGameObjectUseOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GET_MAIL_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetMailList ); + DEFINE_OPCODE_HANDLER(CMSG_GET_MIRRORIMAGE_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMirrorImageDataRequest ); + DEFINE_OPCODE_HANDLER(CMSG_GMRESPONSE_RESOLVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMResponseResolve ); + DEFINE_OPCODE_HANDLER(CMSG_GMSURVEY_SUBMIT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMSurveySubmit ); + DEFINE_OPCODE_HANDLER(CMSG_GMTICKET_CREATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketCreateOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GMTICKET_DELETETICKET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketDeleteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GMTICKET_GETTICKET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketGetTicketOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GMTICKET_SYSTEMSTATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketSystemStatusOpcode); + DEFINE_OPCODE_HANDLER(CMSG_GMTICKET_UPDATETEXT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketUpdateOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GM_REPORT_LAG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReportLag ); + DEFINE_OPCODE_HANDLER(CMSG_GOSSIP_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGossipHelloOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GOSSIP_SELECT_OPTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGossipSelectOptionOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GRANT_LEVEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGrantLevel ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_ASSISTANT_LEADER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupAssistantLeaderOpcode); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_CHANGE_SUB_GROUP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupChangeSubGroupOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_DISBAND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupDisbandOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupInviteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_INVITE_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupInviteResponseOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_RAID_CONVERT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupRaidConvertOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_REQUEST_JOIN_UPDATES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_SET_LEADER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupSetLeaderOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_SET_ROLES, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGroupSetRolesOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_SWAP_SUB_GROUP, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupSwapSubGroupOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GROUP_UNINVITE_GUID, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupUninviteGuidOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_ACCEPT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildAcceptOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_ACHIEVEMENT_MEMBERS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_ACHIEVEMENT_PROGRESS_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildAchievementProgressQuery); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_ADD_RANK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildAddRankOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_ASSIGN_MEMBER_RANK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildAssignRankOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANKER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankerActivate ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_BUY_TAB, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankBuyTab ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_DEPOSIT_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankDepositMoney ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_LOG_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankLogQuery ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_MONEY_WITHDRAWN_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankMoneyWithdrawn ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_QUERY_TAB, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankQueryTab ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_QUERY_TEXT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryGuildBankTabText ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_SWAP_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankSwapItems ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_UPDATE_TAB, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankUpdateTab ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_WITHDRAW_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildBankWithdrawMoney ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_CHANGE_NAME_REQUEST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_DECLINE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildDeclineOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_DEL_RANK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildDelRankOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_DEMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildDemoteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_DISBAND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildDisbandOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_EVENT_LOG_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildEventLogQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_INFO_TEXT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildChangeInfoTextOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildInviteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_LEAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildLeaveOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_MEMBER_SEND_SOR_REQUEST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_MOTD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildMOTDOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_NEWS_UPDATE_STICKY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGuildNewsUpdateStickyOpcode); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_PERMISSIONS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildPermissions ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_PROMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildPromoteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_QUERY, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_QUERY_NEWS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGuildQueryNewsOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_QUERY_RANKS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildQueryRanksOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_REMOVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildRemoveOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_REPLACE_GUILD_MASTER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_REQUEST_CHALLENGE_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_REQUEST_MAX_DAILY_XP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildRequestMaxDailyXP ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_REQUEST_PARTY_STATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildRequestPartyState ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_ROSTER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildRosterOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_SET_ACHIEVEMENT_TRACKING, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_SET_GUILD_MASTER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildSetGuildMaster ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_SET_NOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildSetNoteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_SET_RANK_PERMISSIONS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildSetRankPermissionsOpcode); + DEFINE_OPCODE_HANDLER(CMSG_GUILD_SWITCH_RANK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_HEARTH_AND_RESURRECT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleHearthAndResurrect ); + DEFINE_OPCODE_HANDLER(CMSG_IGNORE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleIgnoreTradeOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_INITIATE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInitiateTradeOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_INSPECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_INSPECT_HONOR_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectHonorStatsOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_INSTANCE_LOCK_WARNING_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_ITEM_REFUND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleItemRefund ); + DEFINE_OPCODE_HANDLER(CMSG_ITEM_REFUND_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleItemRefundInfoRequest ); + DEFINE_OPCODE_HANDLER(CMSG_ITEM_TEXT_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleItemTextQuery ); + DEFINE_OPCODE_HANDLER(CMSG_JOIN_CHANNEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleJoinChannel ); + DEFINE_OPCODE_HANDLER(CMSG_KEEP_ALIVE, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); + DEFINE_OPCODE_HANDLER(CMSG_LEARN_PREVIEW_TALENTS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalents ); + DEFINE_OPCODE_HANDLER(CMSG_LEARN_PREVIEW_TALENTS_PET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnPreviewTalentsPet ); + DEFINE_OPCODE_HANDLER(CMSG_LEARN_TALENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLearnTalentOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LEAVE_CHANNEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLeaveChannel ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_GET_STATUS, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleLfgGetStatus ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_JOIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgJoinOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_LEAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgLeaveOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_LFR_JOIN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_LFR_LEAVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_LOCK_INFO_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleLfgGetLockInfoOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_PROPOSAL_RESULT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgProposalResultOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_SET_BOOT_VOTE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgSetBootVoteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_SET_COMMENT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_SET_ROLES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgSetRolesOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LFG_TELEPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgTeleportOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_ADD_RECRUIT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderAddRecruit ); + DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_BROWSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderBrowse ); + DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_DECLINE_RECRUIT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderDeclineRecruit ); + DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_GET_APPLICATIONS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderGetApplications); + DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_GET_RECRUITS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderGetRecruits ); + DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_POST_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderPostRequest ); + DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_REMOVE_RECRUIT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderRemoveRecruit ); + DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_SET_GUILD_POST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildFinderSetGuildPost ); + DEFINE_OPCODE_HANDLER(CMSG_LIST_INVENTORY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleListInventoryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOAD_SCREEN, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleLoadScreenOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutCancelOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOGOUT_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutRequestOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOG_DISCONNECT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess ); + DEFINE_OPCODE_HANDLER(CMSG_LOOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOOT_CURRENCY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_LOOT_MASTER_GIVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMasterGiveOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOOT_METHOD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMethodOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOOT_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMoneyOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOOT_RELEASE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootReleaseOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_LOOT_ROLL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLootRoll ); + DEFINE_OPCODE_HANDLER(CMSG_MAIL_CREATE_TEXT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailCreateTextItem ); + DEFINE_OPCODE_HANDLER(CMSG_MAIL_DELETE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailDelete ); + DEFINE_OPCODE_HANDLER(CMSG_MAIL_MARK_AS_READ, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailMarkAsRead ); + DEFINE_OPCODE_HANDLER(CMSG_MAIL_RETURN_TO_SENDER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailReturnToSender ); + DEFINE_OPCODE_HANDLER(CMSG_MAIL_TAKE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailTakeItem ); + DEFINE_OPCODE_HANDLER(CMSG_MAIL_TAKE_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMailTakeMoney ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_ADDON_BATTLEGROUND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_ADDON_GUILD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_ADDON_OFFICER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_ADDON_PARTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_ADDON_RAID, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_ADDON_WHISPER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_AFK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_BATTLEGROUND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_CHANNEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_DND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_EMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_GUILD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_OFFICER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_PARTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_RAID, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_RAID_WARNING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_SAY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_WHISPER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MESSAGECHAT_YELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMessagechatOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MINIGAME_MOVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_MOUNTSPECIAL_ANIM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMountSpecialAnimOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_CHNG_TRANSPORT, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FALL_RESET, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FEATHER_FALL_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleFeatherFallAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_FLIGHT_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_PITCH_RATE_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_RUN_BACK_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_RUN_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_SWIM_BACK_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_SWIM_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_TURN_RATE_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_FORCE_WALK_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_HOVER_ACK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMoveHoverAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_KNOCK_BACK_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveKnockBackAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_NOT_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveNotActiveMover ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_SET_CAN_FLY, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_SET_CAN_FLY_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSetCanFlyAckOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_SET_COLLISION_HEIGHT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleSetCollisionHeightAck ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_SPLINE_DONE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSplineDoneOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_TIME_SKIPPED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleMoveTimeSkippedOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_MOVE_WATER_WALK_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveWaterWalkAck ); + DEFINE_OPCODE_HANDLER(CMSG_NAME_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNameQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_NEXT_CINEMATIC_CAMERA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNextCinematicCamera ); + DEFINE_OPCODE_HANDLER(CMSG_NPC_TEXT_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleNpcTextQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_OBJECT_UPDATE_FAILED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleObjectUpdateFailedOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_OBJECT_UPDATE_RESCUED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_OFFER_PETITION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleOfferPetitionOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_OPENING_CINEMATIC, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleOpeningCinematic ); + DEFINE_OPCODE_HANDLER(CMSG_OPEN_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleOpenItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_OPT_OUT_OF_LOOT, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleOptOutOfLootOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PAGE_TEXT_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePageTextQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PARTY_SILENCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_PARTY_UNSILENCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_PETITION_BUY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionBuyOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PETITION_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PETITION_SHOWLIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionShowListOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PETITION_SHOW_SIGNATURES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionShowSignOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PETITION_SIGN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionSignOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PET_ABANDON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetAbandon ); + DEFINE_OPCODE_HANDLER(CMSG_PET_ACTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetAction ); + DEFINE_OPCODE_HANDLER(CMSG_PET_CANCEL_AURA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCancelAuraOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PET_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetCastSpellOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PET_LEARN_TALENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetLearnTalent ); + DEFINE_OPCODE_HANDLER(CMSG_PET_NAME_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetNameQuery ); + DEFINE_OPCODE_HANDLER(CMSG_PET_RENAME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetRename ); + DEFINE_OPCODE_HANDLER(CMSG_PET_SET_ACTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSetAction ); + DEFINE_OPCODE_HANDLER(CMSG_PET_SPELL_AUTOCAST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetSpellAutocastOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PET_STOP_ATTACK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetStopAttack ); + DEFINE_OPCODE_HANDLER(CMSG_PING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess ); + DEFINE_OPCODE_HANDLER(CMSG_PLAYED_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePlayedTime ); + DEFINE_OPCODE_HANDLER(CMSG_PLAYER_LOGIN, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandlePlayerLoginOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_PLAYER_VEHICLE_ENTER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEnterPlayerVehicle ); + DEFINE_OPCODE_HANDLER(CMSG_PLAY_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_PUSHQUESTTOPARTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePushQuestToParty ); + DEFINE_OPCODE_HANDLER(CMSG_PVP_LOG_DATA, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandlePVPLogDataOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_QUERY_BATTLEFIELD_STATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_QUERY_GUILD_MEMBERS_FOR_RECIPE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_QUERY_GUILD_MEMBER_RECIPES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_QUERY_GUILD_RECIPES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_QUERY_GUILD_REWARDS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGuildRewardsQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_QUERY_GUILD_XP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildQueryXPOpcode ); // STATUS_AUTHED + DEFINE_OPCODE_HANDLER(CMSG_QUERY_INSPECT_ACHIEVEMENTS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryInspectAchievements ); + DEFINE_OPCODE_HANDLER(CMSG_QUERY_QUESTS_COMPLETED, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryQuestsCompleted ); + DEFINE_OPCODE_HANDLER(CMSG_QUERY_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryTimeOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_ACCEPT_QUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverAcceptQuestOpcode); + DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_CHOOSE_REWARD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverChooseRewardOpcode); + DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_COMPLETE_QUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverCompleteQuest ); + DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverHelloOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_QUERY_QUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverQueryQuestOpcode); + DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_REQUEST_REWARD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverRequestRewardOpcode); + DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverStatusMultipleQuery); + DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_STATUS_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleQuestgiverStatusQueryOpcode); + DEFINE_OPCODE_HANDLER(CMSG_QUESTLOG_REMOVE_QUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestLogRemoveQuest ); + DEFINE_OPCODE_HANDLER(CMSG_QUEST_CONFIRM_ACCEPT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestConfirmAccept ); + DEFINE_OPCODE_HANDLER(CMSG_QUEST_NPC_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_QUEST_POI_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPOIQuery ); + DEFINE_OPCODE_HANDLER(CMSG_QUEST_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_RANDOMIZE_CHAR_NAME, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleRandomizeCharNameOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_READY_FOR_ACCOUNT_DATA_TIMES, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleReadyForAccountDataTimes ); + DEFINE_OPCODE_HANDLER(CMSG_READ_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReadItem ); + DEFINE_OPCODE_HANDLER(CMSG_REALM_SPLIT, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleRealmSplitOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_RECLAIM_CORPSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReclaimCorpseOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_REDIRECTION_AUTH_PROOF, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_REFORGE_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleReforgeItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_REORDER_CHARACTERS, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleReorderCharacters ); + DEFINE_OPCODE_HANDLER(CMSG_REPAIR_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRepairItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_REPOP_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRepopRequestOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_REPORT_PVP_AFK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReportPvPAFK ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestAccountData ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_CATEGORY_COOLDOWNS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestCategoryCooldowns ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_CEMETERY_LIST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_HOTFIX, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleRequestHotfix ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_INSPECT_RATED_BG_STATS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPartyMemberStatsOpcode); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_PET_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPetInfoOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_PVP_OPTIONS_ENABLED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestPvpOptions ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_PVP_REWARDS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestPvpReward ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RAID_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRaidInfoOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RATED_BG_INFO, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestRatedBgInfo ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RATED_BG_STATS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestRatedBgStats ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RESEARCH_HISTORY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_VEHICLE_EXIT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestVehicleExit ); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_VEHICLE_NEXT_SEAT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_VEHICLE_PREV_SEAT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle); + DEFINE_OPCODE_HANDLER(CMSG_REQUEST_VEHICLE_SWITCH_SEAT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle); + DEFINE_OPCODE_HANDLER(CMSG_RESET_FACTION_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_RESET_INSTANCES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleResetInstancesOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_RESURRECT_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleResurrectResponseOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_RETURN_TO_GRAVEYARD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReturnToGraveyard ); + DEFINE_OPCODE_HANDLER(CMSG_ROLE_POLL_BEGIN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SAVE_CUF_PROFILES, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSaveCUFProfiles ); + DEFINE_OPCODE_HANDLER(CMSG_SELF_RES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSelfResOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SELL_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSellItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SEND_MAIL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSendMail ); + DEFINE_OPCODE_HANDLER(CMSG_SEND_SOR_REQUEST_VIA_ADDRESS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SEND_SOR_REQUEST_VIA_BNET_ACCOUNT_ID, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SETSHEATHED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSetSheathedOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_ACTIONBAR_TOGGLES, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActionBarToggles ); + DEFINE_OPCODE_HANDLER(CMSG_SET_ACTION_BUTTON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActionButtonOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveMoverOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_ACTIVE_VOICE_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveVoiceChannel ); // STATUS_AUTHED + DEFINE_OPCODE_HANDLER(CMSG_SET_ALLOW_LOW_LEVEL_RAID1, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_ALLOW_LOW_LEVEL_RAID2, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_CHANNEL_WATCH, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetChannelWatch ); + DEFINE_OPCODE_HANDLER(CMSG_SET_CONTACT_NOTES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetContactNotesOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_CURRENCY_FLAGS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_EVERYONE_IS_ASSISTANT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_FACTION_ATWAR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetFactionAtWar ); + DEFINE_OPCODE_HANDLER(CMSG_SET_FACTION_INACTIVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetFactionInactiveOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_GUILD_BANK_TEXT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetGuildBankTabText ); + DEFINE_OPCODE_HANDLER(CMSG_SET_PET_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPlayerDeclinedNames ); + DEFINE_OPCODE_HANDLER(CMSG_SET_PREFERED_CEMETERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_PRIMARY_TALENT_TREE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_RELATIVE_POSITION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_SAVED_INSTANCE_EXTEND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetSavedInstanceExtend ); + DEFINE_OPCODE_HANDLER(CMSG_SET_SELECTION, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSetSelectionOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_TAXI_BENCHMARK_MODE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTaxiBenchmarkOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_TITLE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTitleOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_TRADE_CURRENCY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_TRADE_GOLD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeGoldOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SET_VEHICLE_REC_ID_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SET_WATCHED_FACTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetWatchedFactionOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SHOWING_CLOAK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleShowingCloakOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SHOWING_HELM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleShowingHelmOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SOCKET_GEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSocketOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SPELLCLICK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSpellClick ); + DEFINE_OPCODE_HANDLER(CMSG_SPIRIT_HEALER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSpiritHealerActivateOpcode); + DEFINE_OPCODE_HANDLER(CMSG_SPLIT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSplitItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_STANDSTATECHANGE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleStandStateChangeOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_STOP_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SUBMIT_BUG, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SUBMIT_COMPLAIN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SUGGESTION_SUBMIT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SUMMON_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SUSPEND_TOKEN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapInvItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapItem ); + DEFINE_OPCODE_HANDLER(CMSG_SYNC_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_TAXINODE_STATUS_QUERY, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiNodeStatusQueryOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_TAXIQUERYAVAILABLENODES, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes ); + DEFINE_OPCODE_HANDLER(CMSG_TELEPORT_TO_UNIT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_TEXT_EMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTextEmoteOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_TIME_ADJUSTMENT_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_TIME_SYNC_RESP, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleTimeSyncResp ); + DEFINE_OPCODE_HANDLER(CMSG_TIME_SYNC_RESP_FAILED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_TOGGLE_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTogglePvP ); + DEFINE_OPCODE_HANDLER(CMSG_TOTEM_DESTROYED, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTotemDestroyed ); + DEFINE_OPCODE_HANDLER(CMSG_TRAINER_BUY_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerBuySpellOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_TRAINER_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerListOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_TRANSMOGRIFY_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogrifyItems ); + DEFINE_OPCODE_HANDLER(CMSG_TURN_IN_PETITION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTurnInPetitionOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_TUTORIAL_CLEAR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialClear ); + DEFINE_OPCODE_HANDLER(CMSG_TUTORIAL_FLAG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialFlag ); + DEFINE_OPCODE_HANDLER(CMSG_TUTORIAL_RESET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialReset ); + DEFINE_OPCODE_HANDLER(CMSG_UNACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_UNLEARN_SKILL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnlearnSkillOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_UNLEARN_SPECIALIZATION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_UNREGISTER_ALL_ADDON_PREFIXES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnregisterAddonPrefixesOpcode); + DEFINE_OPCODE_HANDLER(CMSG_UPDATE_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateAccountData ); + DEFINE_OPCODE_HANDLER(CMSG_UPDATE_MISSILE_TRAJECTORY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateMissileTrajectory ); + DEFINE_OPCODE_HANDLER(CMSG_UPDATE_PROJECTILE_POSITION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateProjectilePosition ); + DEFINE_OPCODE_HANDLER(CMSG_USED_FOLLOW, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_USE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUseItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_VIOLENCE_LEVEL, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleViolenceLevel ); + DEFINE_OPCODE_HANDLER(CMSG_VOICE_SESSION_ENABLE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleVoiceSessionEnableOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_VOID_STORAGE_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleVoidStorageQuery ); + DEFINE_OPCODE_HANDLER(CMSG_VOID_STORAGE_TRANSFER, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleVoidStorageTransfer ); + DEFINE_OPCODE_HANDLER(CMSG_VOID_STORAGE_UNLOCK, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleVoidStorageUnlock ); + DEFINE_OPCODE_HANDLER(CMSG_VOID_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleVoidSwapItem ); + DEFINE_OPCODE_HANDLER(CMSG_WARDEN_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleWardenDataOpcode ); // STATUS_AUTHED + DEFINE_OPCODE_HANDLER(CMSG_WARGAME_ACCEPT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_WARGAME_START, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_WHO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWhoOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_WHOIS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWhoisOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_WORLD_STATE_UI_TIMER_UPDATE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleWorldStateUITimerUpdate ); + DEFINE_OPCODE_HANDLER(CMSG_WORLD_TELEPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleWorldTeleportOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_WRAP_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleWrapItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_ZONEUPDATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleZoneUpdateOpcode ); + DEFINE_OPCODE_HANDLER(MSG_AUCTION_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionHelloOpcode ); + DEFINE_OPCODE_HANDLER(MSG_CHANNEL_START, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(MSG_CHANNEL_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(MSG_CORPSE_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCorpseQueryOpcode ); + DEFINE_OPCODE_HANDLER(MSG_INSPECT_ARENA_TEAMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectArenaTeamsOpcode ); + DEFINE_OPCODE_HANDLER(MSG_LIST_STABLED_PETS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); + DEFINE_OPCODE_HANDLER(MSG_MINIMAP_PING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMinimapPingOpcode ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_CHARM_TELEPORT_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_FALL_LAND, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_HEARTBEAT, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_JUMP, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_FACING, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_PITCH, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_RUN_MODE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_WALK_MODE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_ASCEND, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_BACKWARD, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_DESCEND, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_FORWARD, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_PITCH_DOWN, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_PITCH_UP, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_STRAFE_LEFT, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_STRAFE_RIGHT, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_SWIM, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_TURN_LEFT, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_START_TURN_RIGHT, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_STOP, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_STOP_ASCEND, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_STOP_PITCH, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_STOP_STRAFE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_STOP_SWIM, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_STOP_TURN, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_TELEPORT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_TELEPORT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveTeleportAck ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_TELEPORT_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_TIME_SKIPPED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_TOGGLE_COLLISION_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(MSG_MOVE_WORLDPORT_ACK, STATUS_TRANSFER, PROCESS_THREADUNSAFE, &WorldSession::HandleMoveWorldportAckOpcode ); + DEFINE_OPCODE_HANDLER(MSG_NOTIFY_PARTY_SQUELCH, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(MSG_PARTY_ASSIGNMENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyAssignmentOpcode ); + DEFINE_OPCODE_HANDLER(MSG_PETITION_DECLINE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionDeclineOpcode ); + DEFINE_OPCODE_HANDLER(MSG_PETITION_RENAME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionRenameOpcode ); + DEFINE_OPCODE_HANDLER(MSG_QUERY_NEXT_MAIL_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryNextMailTime ); + DEFINE_OPCODE_HANDLER(MSG_QUEST_PUSH_RESULT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPushResult ); + DEFINE_OPCODE_HANDLER(MSG_RAID_READY_CHECK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidReadyCheckOpcode ); + DEFINE_OPCODE_HANDLER(MSG_RAID_READY_CHECK_CONFIRM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(MSG_RAID_READY_CHECK_FINISHED, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidReadyCheckFinishedOpcode); + DEFINE_OPCODE_HANDLER(MSG_RAID_TARGET_UPDATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidTargetUpdateOpcode ); + DEFINE_OPCODE_HANDLER(MSG_RANDOM_ROLL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRandomRollOpcode ); + DEFINE_OPCODE_HANDLER(MSG_SAVE_GUILD_EMBLEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSaveGuildEmblemOpcode ); + DEFINE_OPCODE_HANDLER(MSG_SET_DUNGEON_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetDungeonDifficultyOpcode); + DEFINE_OPCODE_HANDLER(MSG_SET_RAID_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetRaidDifficultyOpcode ); + DEFINE_OPCODE_HANDLER(MSG_TABARDVENDOR_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTabardVendorActivateOpcode); + DEFINE_OPCODE_HANDLER(MSG_TALENT_WIPE_CONFIRM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTalentWipeConfirmOpcode ); + DEFINE_OPCODE_HANDLER(MSG_VERIFY_CONNECTIVITY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess ); + DEFINE_OPCODE_HANDLER(SMSG_ACCOUNT_DATA_TIMES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ACCOUNT_INFO_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ACCOUNT_RESTRICTED_WARNING, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ACTION_BUTTONS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ACTIVATETAXIREPLY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ADDON_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ADD_RUNE_POWER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AI_REACTION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AREA_SPIRIT_HEALER_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MESSAGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MOVEMENT_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_ERROR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_UNIT_DESTROYED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_TEAM_COMMAND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_TEAM_EVENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_TEAM_INVITE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_TEAM_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_TEAM_ROSTER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ARENA_TEAM_STATS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ATTACKERSTATEUPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ATTACKSTART, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ATTACKSTOP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ATTACKSWING_BADFACING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ATTACKSWING_CANT_ATTACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ATTACKSWING_DEADTARGET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ATTACKSWING_NOTINRANGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_LIST_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_NOTIFICATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUCTION_COMMAND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUCTION_LIST_PENDING_SALES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUCTION_LIST_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUCTION_OWNER_LIST_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUCTION_OWNER_NOTIFICATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUCTION_REMOVED_NOTIFICATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AURA_POINTS_DEPLETED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AURA_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AURA_UPDATE_ALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUTH_CHALLENGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AUTH_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AVAILABLE_VOICE_CHANNEL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_AVERAGE_ITEM_LEVEL_INFORM, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BARBER_SHOP_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EJECTED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EJECT_PENDING, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_ENTERED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_ENTRY_INVITE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_EXIT_REQUEST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_QUEUE_INVITE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_MGR_STATE_CHANGE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_PLAYER_POSITIONS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_PORT_DENIED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_RATED_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_QUEUED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_ACTIVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_NEEDCONFIRMATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_WAITFORGROUPS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEFIELD_STATUS_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEGROUND_INFO_THROTTLED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_JOINED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_LEFT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BINDER_CONFIRM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BINDPOINTUPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BREAK_TARGET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BUY_BANK_SLOT_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BUY_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_BUY_ITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_ARENA_TEAM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_CLEAR_PENDING_ACTION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_COMMAND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_ALERT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_NOTES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_REMOVED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_REMOVED_ALERT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_UPDATED_ALERT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_FILTER_GUILD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_ADDED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_REMOVED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_RAID_LOCKOUT_UPDATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_SEND_CALENDAR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_SEND_EVENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_SEND_NUM_PENDING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CAMERA_SHAKE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CANCEL_AUTO_REPEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CANCEL_COMBAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CAST_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHANNEL_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHANNEL_MEMBER_COUNT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHARACTER_LOGIN_FAILED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAR_CREATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAR_DELETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAR_ENUM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAR_FACTION_CHANGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAR_RENAME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAT_IGNORED_ACCOUNT_MUTED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAT_NOT_IN_PARTY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAT_PLAYER_AMBIGUOUS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAT_PLAYER_NOT_FOUND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAT_RESTRICTED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAT_SERVER_DISCONNECTED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAT_SERVER_RECONNECTED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CHAT_WRONG_FACTION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CLEAR_BOSS_EMOTES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CLEAR_COOLDOWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CLEAR_COOLDOWNS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CLEAR_TARGET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CLIENTCACHE_VERSION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CLIENT_CONTROL_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMBAT_EVENT_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMMENTATOR_MAP_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMMENTATOR_PARTY_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMMENTATOR_PLAYER_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMMENTATOR_STATE_CHANGED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMPLAIN_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMPRESSED_MOVES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMSAT_CONNECT_FAIL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMSAT_DISCONNECT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COMSAT_RECONNECT_TRY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CONTACT_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CONVERT_RUNE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COOLDOWN_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_COOLDOWN_EVENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CORPSE_NOT_IN_INSTANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CORPSE_RECLAIM_DELAY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CREATURE_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CRITERIA_DELETED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CRITERIA_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CROSSED_INEBRIATION_THRESHOLD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_REMOVED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CURRENCY_LOOT_RESTORED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_CUSTOM_LOAD_SCREEN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DAMAGE_CALC_LOG, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DANCE_QUERY_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DB_REPLY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DEATH_RELEASE_LOC, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DEBUG_RUNE_REGEN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DEFENSE_MESSAGE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DESTROY_OBJECT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DIFFERENT_INSTANCE_FROM_PARTY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DISENCHANT_CREDIT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DISMOUNT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DISMOUNTRESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DISPEL_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DISPLAY_GAME_ERROR, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DONT_AUTO_PUSH_SPELLS_TO_ACTION_BAR, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DROP_NEW_CONNECTION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DUEL_COMPLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DUEL_COUNTDOWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DUEL_INBOUNDS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DUEL_OUTOFBOUNDS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DUEL_REQUESTED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DUEL_WINNER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DUMP_RIDE_TICKETS_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_DURABILITY_DAMAGE_DEATH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ECHO_PARTY_SQUELCH, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_EMOTE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ENABLE_BARBER_SHOP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ENCHANTMENTLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ENVIRONMENTALDAMAGELOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_SAVED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_USE_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_EXPECTED_SPAM_RECORDS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_EXPLORATION_EXPERIENCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FAILED_PLAYER_CONDITION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FEATURE_SYSTEM_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FEIGN_DEATH_RESISTED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FISH_ESCAPED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FISH_NOT_HOOKED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FLIGHT_SPLINE_SYNC, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FLOOD_DETECTED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FORCED_DEATH_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FORCE_SEND_QUEUED_PACKETS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FORCE_SET_VEHICLE_REC_ID, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FORGE_MASTER_SET, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_FRIEND_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAMEOBJECT_CUSTOM_ANIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAMEOBJECT_DESPAWN_ANIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAMEOBJECT_PAGETEXT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAMEOBJECT_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAMEOBJECT_RESET_STATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAMESPEED_SET, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAMETIME_SET, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAMETIME_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAME_EVENT_DEBUG_LOG, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GAME_OBJECT_ACTIVATE_ANIM_KIT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GMRESPONSE_DB_ERROR, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GMRESPONSE_RECEIVED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GMRESPONSE_STATUS_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GMTICKET_CREATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GMTICKET_DELETETICKET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GMTICKET_GETTICKET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GMTICKET_SYSTEMSTATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GMTICKET_UPDATETEXT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GM_MESSAGECHAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GM_TICKET_STATUS_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GODMODE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GOSSIP_COMPLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GOSSIP_MESSAGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GOSSIP_POI, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUPACTION_THROTTLED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUP_CANCEL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUP_DECLINE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUP_DESTROYED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUP_INVITE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUP_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUP_SET_LEADER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUP_SET_ROLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GROUP_UNINVITE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_DELETED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_EARNED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_MEMBERS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_BANK_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_BANK_LOG_QUERY_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_BANK_MONEY_WITHDRAWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_BANK_QUERY_TEXT_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_COMPLETED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_CHALLENGE_UPDATED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_CHANGE_NAME_RESULT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_COMMAND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_COMMAND_RESULT_2, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_CRITERIA_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_CRITERIA_DELETED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_DECLINE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_EVENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_EVENT_LOG_QUERY_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_FLAGGED_FOR_RENAME, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_INVITE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_INVITE_CANCEL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_MAX_DAILY_XP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_MEMBERS_FOR_RECIPE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_MEMBER_DAILY_RESET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_MEMBER_RECIPES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_MEMBER_UPDATE_NOTE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_MOVE_COMPLETE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_MOVE_STARTING, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_NEWS_DELETED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_NEWS_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_PARTY_STATE_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_PERMISSIONS_QUERY_RESULTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_RANK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_RANKS_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_RECIPES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_RENAMED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_REPUTATION_REACTION_CHANGED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_REPUTATION_WEEKLY_CAP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_RESET, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_REWARDS_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_ROSTER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_UPDATE_ROSTER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_XP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_GUILD_XP_GAIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_HEALTH_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_HIGHEST_THREAT_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_HOTFIX_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_HOTFIX_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INITIALIZE_FACTIONS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INITIAL_SPELLS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INIT_CURRENCY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INIT_WORLD_STATES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INSPECT_HONOR_STATS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INSPECT_RATED_BG_STATS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INSPECT_RESULTS_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INSPECT_TALENT, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INSTANCE_LOCK_WARNING_QUERY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INSTANCE_RESET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INSTANCE_RESET_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INSTANCE_SAVE_CREATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INVALIDATE_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INVALIDATE_PLAYER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INVALID_PROMOTION_CODE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_INVENTORY_CHANGE_FAILURE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_ADD_PASSIVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_COOLDOWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_ENCHANT_TIME_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_EXPIRE_PURCHASE_REFUND, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_REFUND_INFO_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_REFUND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_REMOVE_PASSIVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_SEND_PASSIVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_TEXT_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LEARNED_DANCE_MOVES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LEARNED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LEVELUP_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_BOOT_PROPOSAL_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_DISABLED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_JOIN_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_OFFER_CONTINUE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_PARTY_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_PLAYER_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_PLAYER_REWARD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_PROPOSAL_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_QUEUE_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_ROLE_CHECK_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_ROLE_CHOSEN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_SLOT_INVALID, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_TELEPORT_DENIED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_UPDATE_SEARCH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_UPDATE_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LFG_UPDATE_STATUS_NONE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LF_GUILD_APPLICANT_LIST_UPDATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LF_GUILD_APPLICATIONS_LIST_CHANGED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LF_GUILD_BROWSE_UPDATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LF_GUILD_COMMAND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LF_GUILD_MEMBERSHIP_LIST_UPDATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LF_GUILD_POST_UPDATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LF_GUILD_RECRUIT_LIST_UPDATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LIST_INVENTORY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOAD_CUF_PROFILES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOGIN_SETTIMESPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOGIN_VERIFY_WORLD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOGOUT_CANCEL_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOGOUT_COMPLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOGOUT_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOG_XPGAIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_ALL_PASSED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_CLEAR_MONEY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_CONTENTS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_ITEM_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_MASTER_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_MONEY_NOTIFY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_RELEASE_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_REMOVED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_ROLL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_ROLL_WON, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_SLOT_CHANGED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_LOOT_START_ROLL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MAIL_LIST_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MAP_OBJ_EVENTS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MEETINGSTONE_IN_PROGRESS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MESSAGECHAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MESSAGE_BOX, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MINIGAME_SETUP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MINIGAME_STATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MIRRORIMAGE_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MISSILE_CANCEL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MODIFY_COOLDOWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MONEY_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MONSTER_MOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MONSTER_MOVE_TRANSPORT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOTD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOUNTRESULT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOUNTSPECIAL_ANIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_COLLISION_DISABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_COLLISION_ENABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_FEATHER_FALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_DISABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_ENABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_KNOCK_BACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_LAND_WALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_NORMAL_FALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_ROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_ACTIVE_MOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_FLY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_COLLISION_HEIGHT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_COMPOUND_STATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_FLIGHT_BACK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_FLIGHT_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_HOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_PITCH_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_RUN_BACK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_RUN_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_SWIM_BACK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_SWIM_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_TURN_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_WALK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UNROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UNSET_CAN_FLY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UNSET_HOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_COLLISION_HEIGHT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_FLIGHT_SPEED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_KNOCK_BACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_PITCH_RATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_RUN_BACK_SPEED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_RUN_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_SWIM_BACK_SPEED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_SWIM_SPEED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_TELEPORT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_TURN_RATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_UPDATE_WALK_SPEED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MOVE_WATER_WALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_MULTIPLE_PACKETS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_NAME_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_NEW_TAXI_PATH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_NEW_WORLD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_NEW_WORLD_ABORT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_NOTIFICATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_NOTIFY_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_NOTIFY_DEST_LOC_SPELL_CAST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_NPC_TEXT_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_OFFER_PETITION_ERROR, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_OPEN_CONTAINER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_OPEN_LFG_DUNGEON_FINDER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_OVERRIDE_LIGHT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PAGE_TEXT_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PARTYKILLLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PARTY_COMMAND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATS_FULL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PAUSE_MIRROR_TIMER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PERIODICAURALOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PETGODMODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PETITION_ALREADY_SIGNED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PETITION_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PETITION_SHOWLIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PETITION_SHOW_SIGNATURES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PETITION_SIGN_RESULTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_ACTION_FEEDBACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_ACTION_SOUND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_ADDED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_BROKEN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_CAST_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_DISMISS_SOUND, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_GUIDS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_LEARNED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_MODE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_NAME_INVALID, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_NAME_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_REMOVED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_RENAMEABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_SLOT_UPDATED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_SPELLS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_TAME_FAILURE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PET_UPDATE_COMBO_POINTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAYED_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAYERBINDERROR, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAYERBOUND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAYER_DIFFICULTY_CHANGE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAYER_MOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAYER_SKINNED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAYER_VEHICLE_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAY_DANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAY_MUSIC, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAY_OBJECT_SOUND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAY_ONE_SHOT_ANIM_KIT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAY_SOUND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAY_SPELL_VISUAL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAY_SPELL_VISUAL_KIT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PLAY_TIME_WARNING, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PONG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_POWER_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PRE_RESURRECT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PROCRESIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PROPOSE_LEVEL_GRANT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PVP_CREDIT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PVP_LOG_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_PVP_OPTIONS_ENABLED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUERY_TIME_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_OFFER_REWARD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_COMPLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_DETAILS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_INVALID, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_REQUEST_ITEMS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTGIVER_STATUS_MULTIPLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTLOG_FULL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_KILL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_PVP_KILL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTUPDATE_COMPLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTUPDATE_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUESTUPDATE_FAILEDTIMER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUEST_CONFIRM_ACCEPT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUEST_FORCE_REMOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUEST_NPC_QUERY_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUEST_POI_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_QUEST_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RAID_GROUP_ONLY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RAID_INSTANCE_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RAID_INSTANCE_MESSAGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RAID_MARKERS_CHANGED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RAID_READY_CHECK_THROTTLED_ERROR, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RAID_SUMMON_FAILED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RANDOMIZE_CHAR_NAME, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RATED_BG_RATING, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RATED_BG_STATS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_READ_ITEM_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_READ_ITEM_OK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REALM_SPLIT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REAL_GROUP_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RECEIVED_MAIL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REDIRECT_CLIENT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_EXPIRED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_FAILURE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REFORGE_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REMOVED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REPORT_PVP_AFK_RESULT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REQUEST_CEMETERY_LIST_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_REQUEST_PVP_REWARDS_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RESEARCH_COMPLETE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RESEARCH_SETUP_HISTORY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RESET_COMPRESSION_CONTEXT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RESET_FAILED_NOTIFY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RESURRECT_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RESYNC_RUNES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ROLE_POLL_BEGIN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_RWHOIS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SELL_ITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SEND_MAIL_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SEND_UNLEARN_SPELLS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SERVERTIME, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SERVER_FIRST_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SERVER_INFO_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SERVER_MESSAGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SERVER_PERF, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_DF_FAST_LAUNCH_RESULT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_FACTION_ATWAR, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_FACTION_STANDING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_FACTION_VISIBLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_FLAT_SPELL_MODIFIER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_FORCED_REACTIONS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_PCT_SPELL_MODIFIER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_PROJECTILE_POSITION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SHOWTAXINODES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SHOW_BANK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SHOW_MAILBOX, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SHOW_RATINGS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SOCKET_GEMS_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SOR_START_EXPERIENCE_INCOMPLETE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLBREAKLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLDAMAGESHIELD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLDISPELLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLENERGIZELOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLHEALLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLINSTAKILLLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLINTERRUPTLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLLOGEXECUTE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLLOGMISS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLNONMELEEDAMAGELOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLORDAMAGE_IMMUNE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELLSTEALLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELL_CATEGORY_COOLDOWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELL_COOLDOWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELL_DELAYED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELL_FAILED_OTHER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELL_FAILURE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELL_GO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELL_START, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPELL_UPDATE_CHAIN_TARGETS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPIRIT_HEALER_CONFIRM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_COLLISION_DISABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_COLLISION_ENABLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_DISABLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_ENABLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_ROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_ANIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FEATHER_FALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLIGHT_BACK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLIGHT_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_FLYING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_HOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_LAND_WALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_NORMAL_FALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_PITCH_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_MODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_RUN_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_SWIM_BACK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_SWIM_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_TURN_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WALK_MODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WALK_SPEED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_SET_WATER_WALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_START_SWIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_STOP_SWIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNSET_FLYING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SPLINE_MOVE_UNSET_HOVER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_STABLE_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_STANDSTATE_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_START_MIRROR_TIMER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_START_TIMER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_STOP_DANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_STOP_MIRROR_TIMER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_STREAMING_MOVIE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SUMMON_CANCEL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SUMMON_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SUPPRESS_NPC_GREETINGS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TALENTS_ERROR, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TALENTS_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TAXINODE_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TEST_DROP_RATE_RESULT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TEXT_EMOTE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_THREAT_CLEAR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_THREAT_REMOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_THREAT_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TIME_ADJUSTMENT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TIME_SYNC_REQ, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TITLE_EARNED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TOGGLE_XP_GAIN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TOTEM_CREATED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRADE_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRADE_STATUS_EXTENDED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRAINER_BUY_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRAINER_BUY_SUCCEEDED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRAINER_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRANSFER_ABORTED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRANSFER_PENDING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRIGGER_CINEMATIC, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TRIGGER_MOVIE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TURN_IN_PETITION_RESULTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_TUTORIAL_FLAGS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UNIT_HEALTH_FREQUENT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UNIT_SPELLCAST_START, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_ACCOUNT_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_COMBO_POINTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_CURRENCY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_CURRENCY_WEEK_LIMIT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_DUNGEON_ENCOUNTER_FOR_LOOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_OWNERSHIP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_LAST_INSTANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_OBJECT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_SERVER_PLAYER_POSITION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_UPDATE_WORLD_STATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_USERLIST_ADD, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_USERLIST_REMOVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_USERLIST_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOICESESSION_FULL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOICE_CHAT_STATUS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOICE_PARENTAL_CONTROLS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOICE_SESSION_LEAVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOICE_SESSION_ROSTER_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOICE_SET_TALKER_MUTED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_ITEM_SWAP_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_STORAGE_CONTENTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_STORAGE_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_STORAGE_TRANSFER_CHANGES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_TRANSFER_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WAIT_QUEUE_FINISH, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WAIT_QUEUE_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WARDEN_DATA, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WARGAME_CHECK_ENTRY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WARGAME_REQUEST_SENT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WEATHER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WEEKLY_LAST_RESET, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WEEKLY_RESET_CURRENCY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WEEKLY_SPELL_USAGE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WEEKLY_SPELL_USAGE_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WHO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WHOIS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WORLD_SERVER_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_WORLD_STATE_UI_TIMER_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_XP_GAIN_ABORTED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ZONE_UNDER_ATTACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + + // These opcodes are not in WPP + + //DEFINE_OPCODE_HANDLER(CMSG_ACTIVE_PVP_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_ADD_PVP_MEDAL_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_ADVANCE_SPAWN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_AFK_MONITOR_INFO_CLEAR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_AFK_MONITOR_INFO_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_AUTH_SRP6_BEGIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_AUTH_SRP6_PROOF, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_AUTH_SRP6_RECODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_AUTOEQUIP_GROUND_ITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_GROUND_ITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_JOIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_MANAGER_ADVANCE_STATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_MANAGER_SET_NEXT_TRANSITION_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_REQUEST_SCORE_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); Need to send the response + //DEFINE_OPCODE_HANDLER(CMSG_BATTLEMASTER_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlemasterHelloOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_BEASTMASTER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BOOTME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BOT_DETECTED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BOT_DETECTED2, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BUY_ITEM_IN_SLOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyItemInSlotOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_BUY_LOTTERY_TICKET_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_BUY_STABLE_SLOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBuyStableSlot ); + //DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_CONTEXT_EVENT_SIGNUP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CALENDAR_EVENT_INVITE_NOTES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CANCEL_GROWTH_AURA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelGrowthAuraOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_CHANGE_GDF_ARENA_RATING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHANGE_PERSONAL_ARENA_RATING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHARACTER_POINT_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHEAT_PLAYER_LOGIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHEAT_PLAYER_LOOKUP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHEAT_SETMONEY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHEAT_SET_ARENA_CURRENCY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHEAT_SET_HONOR_CURRENCY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CHECK_LOGIN_CRITERIA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CLEAR_EXPLORATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CLEAR_HOLIDAY_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CLEAR_QUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CLEAR_RANDOM_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CLEAR_SERVER_BUCK_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_COMPLETE_ACHIEVEMENT_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CONTROLLER_EJECT_PASSENGER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEjectPassenger ); + //DEFINE_OPCODE_HANDLER(CMSG_COOLDOWN_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CREATEGAMEOBJECT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CREATEITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_CREATEMONSTER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DBLOOKUP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DEBUG_ACTIONS_START, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DEBUG_ACTIONS_STOP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DEBUG_AISTATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DEBUG_CHANGECELLZONE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DEBUG_LIST_TARGETS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DEBUG_PASSIVE_AURA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DEBUG_SERVER_GEO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DECHARGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DECLINE_CHANNEL_INVITE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleChannelDeclineInvite ); + //DEFINE_OPCODE_HANDLER(CMSG_DELETE_DANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DEL_PVP_MEDAL_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DESTROYMONSTER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DESTROY_ITEMS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DISABLE_PVP_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DROP_NEW_CONNECTION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_DUMP_OBJECTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_ENABLE_DAMAGE_LOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_END_BATTLEFIELD_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_EXPIRE_RAID_INSTANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_FLAG_QUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_FLAG_QUEST_FINISH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_FLOOD_GRACE_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_FORCEACTION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_FORCEACTIONONOTHER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_FORCEACTIONSHOW, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_FORCE_ANIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_FORCE_SAY_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GAMESPEED_SET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GAMETIME_SET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GETDEATHBINDZONE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GET_CHANNEL_MEMBER_COUNT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetChannelMemberCount ); + //DEFINE_OPCODE_HANDLER(CMSG_GHOST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GMRESPONSE_CREATE_TICKET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_CHARACTER_RESTORE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_CHARACTER_SAVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_CREATE_ITEM_TARGET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_DESTROY_ONLINE_CORPSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_FREEZE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_GRANT_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_INVIS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_MOVECORPSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_NUKE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_NUKE_ACCOUNT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_NUKE_CHARACTER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_REMOVE_ACHIEVEMENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_REQUEST_PLAYER_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_RESURRECT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_REVEALTO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_SET_CRITERIA_FOR_PLAYER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_SET_SECURITY_GROUP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_SHOW_COMPLAINTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_SILENCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_SUMMONMOB, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_TEACH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_UBERINVIS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_UNSQUELCH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_UNTEACH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_UPDATE_TICKET_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_VISION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GM_WHISPER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GODMODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GROUP_CANCEL, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GROUP_UNINVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupUninviteOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_GUILD_BANK_NOTE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_GUILD_CREATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildCreateOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_GUILD_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildInfoOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_IGNORE_KNOCKBACK_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_IGNORE_REQUIREMENTS_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_INSTANCE_LOCK_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInstanceLockResponse ); + //DEFINE_OPCODE_HANDLER(CMSG_LEARN_DANCE_MOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_LEARN_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_LEVEL_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_LFG_SET_NEEDS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_LF_GUILD_JOIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_LOAD_DANCES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_LOTTERY_QUERY_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_LUA_USAGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MAELSTROM_GM_SENT_MAIL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MAELSTROM_INVALIDATE_CACHE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MAELSTROM_RENAME_GUILD, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MAKEMONSTERATTACKGUID, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(SMSG_MEETINGSTONE_COMPLETE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(CMSG_MEETINGSTONE_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MOVE_CHARACTER_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MOVE_CHARM_PORT_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MOVE_CHARM_TELEPORT_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MOVE_ENABLE_SWIM_TO_FLY_TRANS_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MOVE_SET_RELATIVE_POSITION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MOVE_SET_VEHICLE_REC_ID_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MOVE_START_SWIM_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_MOVE_STOP_SWIM_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_NEW_SPELL_SLOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_NO_SPELL_VARIANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PERFORM_ACTION_SET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PETGODMODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PET_LEVEL_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PET_NAME_CACHE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PET_UNLEARN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PET_UNLEARN_TALENTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PLAYER_AI_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PLAYER_DIFFICULTY_CHANGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PLAYER_LOGOUT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePlayerLogoutOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_PROFILEDATA_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_PVP_QUEUE_STATS_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_QUERY_GUILD_MAX_XP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_QUERY_OBJECT_POSITION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_QUERY_OBJECT_ROTATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_QUERY_SERVER_BUCK_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_QUERY_VEHICLE_STATUS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_CANCEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverCancel ); + //DEFINE_OPCODE_HANDLER(CMSG_QUESTGIVER_QUEST_AUTOLAUNCH, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverQuestAutoLaunch ); + //DEFINE_OPCODE_HANDLER(CMSG_QUESTLOG_SWAP_QUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestLogSwapQuest ); + //DEFINE_OPCODE_HANDLER(CMSG_RECHARGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_REDIRECTION_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_REFER_A_FRIEND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_REMOVE_GLYPH, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRemoveGlyph ); + //DEFINE_OPCODE_HANDLER(CMSG_REPLACE_ACCOUNT_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_RUN_SCRIPT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SAVE_DANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SAVE_PLAYER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SEARCH_LFG_JOIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrJoinOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_SEARCH_LFG_LEAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrLeaveOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_SEND_COMBAT_TRIGGER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SEND_EVENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SEND_GENERAL_TRIGGER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SEND_LOCAL_EVENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SERVERINFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SERVERTIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SERVER_BROADCAST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SERVER_COMMAND, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SERVER_INFO_QUERY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SETDEATHBINDPOINT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_ARENA_MEMBER_SEASON_GAMES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_ARENA_MEMBER_WEEKLY_GAMES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_ARENA_TEAM_RATING_BY_INDEX, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_ARENA_TEAM_SEASON_GAMES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_ARENA_TEAM_WEEKLY_GAMES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_BREATH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_CHARACTER_MODEL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_CRITERIA_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_DURABILITY_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_EXPLORATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_EXPLORATION_ALL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_FACTION_CHEAT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetFactionCheat ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_GLYPH, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_GLYPH_SLOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_GRANTABLE_LEVELS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_LFG_COMMENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfgSetCommentOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_PAID_SERVICE_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_PVP_RANK_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_PVP_TITLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_RUNE_COOLDOWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_RUNE_COUNT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_SKILL_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_STAT_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_TITLE_SUFFIX, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SET_WORLDSTATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SKILL_BUY_RANK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SKILL_BUY_STEP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_STABLE_PET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleStablePet ); + //DEFINE_OPCODE_HANDLER(CMSG_STABLE_REVIVE_PET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleStableRevivePet ); + //DEFINE_OPCODE_HANDLER(CMSG_STABLE_SWAP_PET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleStableSwapPet ); + //DEFINE_OPCODE_HANDLER(CMSG_START_BATTLEFIELD_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_START_QUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_STORE_LOOT_IN_SLOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_SUSPEND_COMMS_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TARGET_CAST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TARGET_SCRIPT_CAST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TAXICLEARALLNODES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TAXICLEARNODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TAXIENABLEALLNODES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TAXIENABLENODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TAXISHOWNODES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TEST_DROP_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TOGGLE_XP_GAIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_TRIGGER_CINEMATIC_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_UNCLAIM_LICENSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_UNDRESSPLAYER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_UNITANIMTIER_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_UNLEARN_DANCE_MOVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_UNLEARN_SPELL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_UNLEARN_TALENTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_UNSTABLE_PET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnstablePet ); + //DEFINE_OPCODE_HANDLER(CMSG_UNUSED5, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_UNUSED6, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_USE_SKILL_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_VOICE_SET_TALKER_MUTED_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_WEATHER_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_XP_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(CMSG_ZONE_MAP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_DELAY_GHOST_TELEPORT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_DEV_SHOWLABEL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_GM_ACCOUNT_ONLINE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_GM_BIND_OTHER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_GM_CHANGE_ARENA_RATING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_GM_DESTROY_CORPSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_GM_GEARRATING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_GM_RESETINSTANCELIMIT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_GM_SHOWLABEL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_GM_SUMMON, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_ALL_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_FLIGHT_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_PITCH_RATE_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_RAW_POSITION_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_RUN_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_SWIM_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_TURN_RATE_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_SET_WALK_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_START_SWIM_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_STOP_SWIM_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_TOGGLE_FALL_LOGGING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_MOVE_TOGGLE_LOGGING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_NULL_ACTION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(MSG_PVP_LOG_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePVPLogDataOpcode ); + //DEFINE_OPCODE_HANDLER(MSG_VIEW_PHASE_SHIFT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + //DEFINE_OPCODE_HANDLER(SMSG_AFK_MONITOR_INFO_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_AURACASTLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_BINDZONEREPLY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_ACTION_PENDING, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CALENDAR_UPDATE_INVITE_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CHANGEPLAYER_DIFFICULTY_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CHARACTER_PROFILE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CHARACTER_PROFILE_REALM_CONNECTED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CHEAT_PLAYER_LOOKUP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CHECK_FOR_BOTS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_COMBAT_LOG_MULTIPLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_COMMENTATOR_GET_PLAYER_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_COMPLETION_NPC_RESPONCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_CORPSE_IS_NOT_IN_INSTANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_DAMAGE_DONE_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_DBLOOKUP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_DEBUGAURAPROC, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_DEBUG_AISTATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_DEBUG_LIST_TARGETS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_DEBUG_SERVER_GEO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_DUMP_OBJECTS_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_DYNAMIC_DROP_ROLL_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_FORCEACTIONSHOW, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_FORCE_ANIM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_FORCE_DISPLAY_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GAMETIMEBIAS_SET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GHOSTEE_GONE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GMRESPONSE_CREATE_TICKET, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GOGOGO_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GUILD_CANCEL, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GUILD_INFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GUILD_KNOWN_RECIPES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GUILD_SET_NOTE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GUILD_TRADESKILL_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_GUILD_XP_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_IGNORE_REQUIREMENTS_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_INSPECT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_JOINED_BATTLEGROUND_QUEUE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_KICK_REASON, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_LFG_OPEN_FROM_GOSSIP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_LFG_UPDATE_LIST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_LF_GUILD_SEARCH_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_LOTTERY_QUERY_RESULT_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_LOTTERY_RESULT_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_MEETINGSTONE_MEMBER_ADDED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_MEETINGSTONE_SETQUEUE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_MINIGAME_MOVE_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_MOVE_CHARACTER_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_VEHICLE_REC_ID, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_MOVE_SET_WALK_IN_AIR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_MOVE_SKIP_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_MOVE_UNSET_WALK_IN_AIR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_NPC_WONT_TALK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_PET_UNLEARN_CONFIRM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_PLAYER_UNK_DEAD_ALIVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_PROFILEDATA_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_PUREMOUNT_CANCELLED_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_PVP_QUEUE_STATS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_QUERY_OBJECT_POSITION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_QUERY_OBJECT_ROTATION, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_RAID_READY_CHECK_ERROR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_REMOVED_FROM_PVP_QUEUE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_RESET_RANGED_COMBAT_TIMER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_RESISTLOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_RESUME_CAST_BAR, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_RESURRECT_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SCRIPT_MESSAGE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SEND_ALL_COMBAT_LOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SERVERINFO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SERVER_BUCK_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SERVER_BUCK_DATA_START, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SET_EXTRA_AURA_INFO_OBSOLETE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SPELL_CHANCE_PROC_LOG, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_SPELL_CHANCE_RESIST_PUSHBACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_VOICE_SESSION_ADJUST_PRIORITY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_VOICE_SESSION_ENABLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + //DEFINE_OPCODE_HANDLER(SMSG_ZONE_MAP, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + +#undef DEFINE_OPCODE_HANDLER }; diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 7b07abdf962..4047b1b42c5 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -28,1318 +28,1353 @@ /// List of Opcodes enum Opcodes { - MSG_NULL_ACTION = 0x000, - CMSG_BOOTME = 0x001, - CMSG_DBLOOKUP = 0x002, - SMSG_DBLOOKUP = 0x003, - CMSG_QUERY_OBJECT_POSITION = 0x004, - SMSG_QUERY_OBJECT_POSITION = 0x005, - CMSG_QUERY_OBJECT_ROTATION = 0x006, - SMSG_QUERY_OBJECT_ROTATION = 0x007, - CMSG_WORLD_TELEPORT = 0x008, - CMSG_TELEPORT_TO_UNIT = 0x009, - CMSG_ZONE_MAP = 0x00A, - SMSG_ZONE_MAP = 0x00B, - CMSG_DEBUG_CHANGECELLZONE = 0x00C, - CMSG_MOVE_CHARACTER_CHEAT = 0x00D, - SMSG_MOVE_CHARACTER_CHEAT = 0x00E, - CMSG_RECHARGE = 0x00F, - CMSG_LEARN_SPELL = 0x010, - CMSG_CREATEMONSTER = 0x011, - CMSG_DESTROYMONSTER = 0x012, - CMSG_CREATEITEM = 0x013, - CMSG_CREATEGAMEOBJECT = 0x014, - SMSG_CHECK_FOR_BOTS = 0x015, - CMSG_MAKEMONSTERATTACKGUID = 0x016, - CMSG_BOT_DETECTED2 = 0x017, - CMSG_FORCEACTION = 0x018, - CMSG_FORCEACTIONONOTHER = 0x019, - CMSG_FORCEACTIONSHOW = 0x01A, - SMSG_FORCEACTIONSHOW = 0x01B, - CMSG_PETGODMODE = 0x01C, - SMSG_PETGODMODE = 0x01D, - SMSG_REFER_A_FRIEND_EXPIRED = 0x01E, - CMSG_WEATHER_SPEED_CHEAT = 0x01F, - CMSG_UNDRESSPLAYER = 0x020, - CMSG_BEASTMASTER = 0x021, - CMSG_GODMODE = 0x022, - SMSG_GODMODE = 0x023, - CMSG_CHEAT_SETMONEY = 0x024, - CMSG_LEVEL_CHEAT = 0x025, - CMSG_PET_LEVEL_CHEAT = 0x026, - CMSG_SET_WORLDSTATE = 0x027, - CMSG_COOLDOWN_CHEAT = 0x028, - CMSG_USE_SKILL_CHEAT = 0x029, - CMSG_FLAG_QUEST = 0x02A, - CMSG_FLAG_QUEST_FINISH = 0x02B, - CMSG_CLEAR_QUEST = 0x02C, - CMSG_SEND_EVENT = 0x02D, - CMSG_DEBUG_AISTATE = 0x02E, - SMSG_DEBUG_AISTATE = 0x02F, - CMSG_DISABLE_PVP_CHEAT = 0x030, - CMSG_ADVANCE_SPAWN_TIME = 0x031, - SMSG_DESTRUCTIBLE_BUILDING_DAMAGE = 0x032, - CMSG_AUTH_SRP6_BEGIN = 0x033, - CMSG_AUTH_SRP6_PROOF = 0x034, - CMSG_AUTH_SRP6_RECODE = 0x035, - CMSG_CHAR_CREATE = 0x036, - CMSG_CHAR_ENUM = 0x037, - CMSG_CHAR_DELETE = 0x038, - SMSG_AUTH_SRP6_RESPONSE = 0x039, - SMSG_CHAR_CREATE = 0x03A, - SMSG_CHAR_ENUM = 0x03B, - SMSG_CHAR_DELETE = 0x03C, - CMSG_PLAYER_LOGIN = 0x03D, - SMSG_NEW_WORLD = 0x03E, - SMSG_TRANSFER_PENDING = 0x03F, - SMSG_TRANSFER_ABORTED = 0x040, - SMSG_CHARACTER_LOGIN_FAILED = 0x041, - SMSG_LOGIN_SETTIMESPEED = 0x042, - SMSG_GAMETIME_UPDATE = 0x043, - CMSG_GAMETIME_SET = 0x044, - SMSG_GAMETIME_SET = 0x045, - CMSG_GAMESPEED_SET = 0x046, - SMSG_GAMESPEED_SET = 0x047, - CMSG_SERVERTIME = 0x048, - SMSG_SERVERTIME = 0x049, - CMSG_PLAYER_LOGOUT = 0x04A, - CMSG_LOGOUT_REQUEST = 0x04B, - SMSG_LOGOUT_RESPONSE = 0x04C, - SMSG_LOGOUT_COMPLETE = 0x04D, - CMSG_LOGOUT_CANCEL = 0x04E, - SMSG_LOGOUT_CANCEL_ACK = 0x04F, - CMSG_NAME_QUERY = 0x050, - SMSG_NAME_QUERY_RESPONSE = 0x051, - CMSG_PET_NAME_QUERY = 0x052, - SMSG_PET_NAME_QUERY_RESPONSE = 0x053, - CMSG_GUILD_QUERY = 0x054, - SMSG_GUILD_QUERY_RESPONSE = 0x055, - CMSG_ITEM_QUERY_SINGLE = 0x056, - CMSG_ITEM_QUERY_MULTIPLE = 0x057, - SMSG_ITEM_QUERY_SINGLE_RESPONSE = 0x058, - SMSG_ITEM_QUERY_MULTIPLE_RESPONSE = 0x059, - CMSG_PAGE_TEXT_QUERY = 0x05A, - SMSG_PAGE_TEXT_QUERY_RESPONSE = 0x05B, - CMSG_QUEST_QUERY = 0x05C, - SMSG_QUEST_QUERY_RESPONSE = 0x05D, - CMSG_GAMEOBJECT_QUERY = 0x05E, - SMSG_GAMEOBJECT_QUERY_RESPONSE = 0x05F, - CMSG_CREATURE_QUERY = 0x060, - SMSG_CREATURE_QUERY_RESPONSE = 0x061, - CMSG_WHO = 0x062, - SMSG_WHO = 0x063, - CMSG_WHOIS = 0x064, - SMSG_WHOIS = 0x065, - CMSG_CONTACT_LIST = 0x066, - SMSG_CONTACT_LIST = 0x067, - SMSG_FRIEND_STATUS = 0x068, - CMSG_ADD_FRIEND = 0x069, - CMSG_DEL_FRIEND = 0x06A, - CMSG_SET_CONTACT_NOTES = 0x06B, - CMSG_ADD_IGNORE = 0x06C, - CMSG_DEL_IGNORE = 0x06D, - CMSG_GROUP_INVITE = 0x06E, - SMSG_GROUP_INVITE = 0x06F, - CMSG_GROUP_CANCEL = 0x070, - SMSG_GROUP_CANCEL = 0x071, - CMSG_GROUP_ACCEPT = 0x072, - CMSG_GROUP_DECLINE = 0x073, - SMSG_GROUP_DECLINE = 0x074, - CMSG_GROUP_UNINVITE = 0x075, - CMSG_GROUP_UNINVITE_GUID = 0x076, - SMSG_GROUP_UNINVITE = 0x077, - CMSG_GROUP_SET_LEADER = 0x078, - SMSG_GROUP_SET_LEADER = 0x079, - CMSG_LOOT_METHOD = 0x07A, - CMSG_GROUP_DISBAND = 0x07B, - SMSG_GROUP_DESTROYED = 0x07C, - SMSG_GROUP_LIST = 0x07D, - SMSG_PARTY_MEMBER_STATS = 0x07E, - SMSG_PARTY_COMMAND_RESULT = 0x07F, - UMSG_UPDATE_GROUP_MEMBERS = 0x080, - CMSG_GUILD_CREATE = 0x081, - CMSG_GUILD_INVITE = 0x082, - SMSG_GUILD_INVITE = 0x083, - CMSG_GUILD_ACCEPT = 0x084, - CMSG_GUILD_DECLINE = 0x085, - SMSG_GUILD_DECLINE = 0x086, - CMSG_GUILD_INFO = 0x087, - SMSG_GUILD_INFO = 0x088, - CMSG_GUILD_ROSTER = 0x089, - SMSG_GUILD_ROSTER = 0x08A, - CMSG_GUILD_PROMOTE = 0x08B, - CMSG_GUILD_DEMOTE = 0x08C, - CMSG_GUILD_LEAVE = 0x08D, - CMSG_GUILD_REMOVE = 0x08E, - CMSG_GUILD_DISBAND = 0x08F, - CMSG_GUILD_LEADER = 0x090, - CMSG_GUILD_MOTD = 0x091, - SMSG_GUILD_EVENT = 0x092, - SMSG_GUILD_COMMAND_RESULT = 0x093, - UMSG_UPDATE_GUILD = 0x094, - CMSG_MESSAGECHAT = 0x095, - SMSG_MESSAGECHAT = 0x096, - CMSG_JOIN_CHANNEL = 0x097, - CMSG_LEAVE_CHANNEL = 0x098, - SMSG_CHANNEL_NOTIFY = 0x099, - CMSG_CHANNEL_LIST = 0x09A, - SMSG_CHANNEL_LIST = 0x09B, - CMSG_CHANNEL_PASSWORD = 0x09C, - CMSG_CHANNEL_SET_OWNER = 0x09D, - CMSG_CHANNEL_OWNER = 0x09E, - CMSG_CHANNEL_MODERATOR = 0x09F, - CMSG_CHANNEL_UNMODERATOR = 0x0A0, - CMSG_CHANNEL_MUTE = 0x0A1, - CMSG_CHANNEL_UNMUTE = 0x0A2, - CMSG_CHANNEL_INVITE = 0x0A3, - CMSG_CHANNEL_KICK = 0x0A4, - CMSG_CHANNEL_BAN = 0x0A5, - CMSG_CHANNEL_UNBAN = 0x0A6, - CMSG_CHANNEL_ANNOUNCEMENTS = 0x0A7, - CMSG_CHANNEL_MODERATE = 0x0A8, - SMSG_UPDATE_OBJECT = 0x0A9, - SMSG_DESTROY_OBJECT = 0x0AA, - CMSG_USE_ITEM = 0x0AB, - CMSG_OPEN_ITEM = 0x0AC, - CMSG_READ_ITEM = 0x0AD, - SMSG_READ_ITEM_OK = 0x0AE, - SMSG_READ_ITEM_FAILED = 0x0AF, - SMSG_ITEM_COOLDOWN = 0x0B0, - CMSG_GAMEOBJ_USE = 0x0B1, - CMSG_DESTROY_ITEMS = 0x0B2, - SMSG_GAMEOBJECT_CUSTOM_ANIM = 0x0B3, - CMSG_AREATRIGGER = 0x0B4, - MSG_MOVE_START_FORWARD = 0x0B5, - MSG_MOVE_START_BACKWARD = 0x0B6, - MSG_MOVE_STOP = 0x0B7, - MSG_MOVE_START_STRAFE_LEFT = 0x0B8, - MSG_MOVE_START_STRAFE_RIGHT = 0x0B9, - MSG_MOVE_STOP_STRAFE = 0x0BA, - MSG_MOVE_JUMP = 0x0BB, - MSG_MOVE_START_TURN_LEFT = 0x0BC, - MSG_MOVE_START_TURN_RIGHT = 0x0BD, - MSG_MOVE_STOP_TURN = 0x0BE, - MSG_MOVE_START_PITCH_UP = 0x0BF, - MSG_MOVE_START_PITCH_DOWN = 0x0C0, - MSG_MOVE_STOP_PITCH = 0x0C1, - MSG_MOVE_SET_RUN_MODE = 0x0C2, - MSG_MOVE_SET_WALK_MODE = 0x0C3, - MSG_MOVE_TOGGLE_LOGGING = 0x0C4, - MSG_MOVE_TELEPORT = 0x0C5, - MSG_MOVE_TELEPORT_CHEAT = 0x0C6, - MSG_MOVE_TELEPORT_ACK = 0x0C7, - MSG_MOVE_TOGGLE_FALL_LOGGING = 0x0C8, - MSG_MOVE_FALL_LAND = 0x0C9, - MSG_MOVE_START_SWIM = 0x0CA, - MSG_MOVE_STOP_SWIM = 0x0CB, - MSG_MOVE_SET_RUN_SPEED_CHEAT = 0x0CC, - MSG_MOVE_SET_RUN_SPEED = 0x0CD, - MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT = 0x0CE, - MSG_MOVE_SET_RUN_BACK_SPEED = 0x0CF, - MSG_MOVE_SET_WALK_SPEED_CHEAT = 0x0D0, - MSG_MOVE_SET_WALK_SPEED = 0x0D1, - MSG_MOVE_SET_SWIM_SPEED_CHEAT = 0x0D2, - MSG_MOVE_SET_SWIM_SPEED = 0x0D3, - MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT = 0x0D4, - MSG_MOVE_SET_SWIM_BACK_SPEED = 0x0D5, - MSG_MOVE_SET_ALL_SPEED_CHEAT = 0x0D6, - MSG_MOVE_SET_TURN_RATE_CHEAT = 0x0D7, - MSG_MOVE_SET_TURN_RATE = 0x0D8, - MSG_MOVE_TOGGLE_COLLISION_CHEAT = 0x0D9, - MSG_MOVE_SET_FACING = 0x0DA, - MSG_MOVE_SET_PITCH = 0x0DB, - MSG_MOVE_WORLDPORT_ACK = 0x0DC, - SMSG_MONSTER_MOVE = 0x0DD, - SMSG_MOVE_WATER_WALK = 0x0DE, - SMSG_MOVE_LAND_WALK = 0x0DF, - CMSG_MOVE_CHARM_PORT_CHEAT = 0x0E0, - CMSG_MOVE_SET_RAW_POSITION = 0x0E1, - SMSG_FORCE_RUN_SPEED_CHANGE = 0x0E2, - CMSG_FORCE_RUN_SPEED_CHANGE_ACK = 0x0E3, - SMSG_FORCE_RUN_BACK_SPEED_CHANGE = 0x0E4, - CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK = 0x0E5, - SMSG_FORCE_SWIM_SPEED_CHANGE = 0x0E6, - CMSG_FORCE_SWIM_SPEED_CHANGE_ACK = 0x0E7, - SMSG_FORCE_MOVE_ROOT = 0x0E8, - CMSG_FORCE_MOVE_ROOT_ACK = 0x0E9, - SMSG_FORCE_MOVE_UNROOT = 0x0EA, - CMSG_FORCE_MOVE_UNROOT_ACK = 0x0EB, - MSG_MOVE_ROOT = 0x0EC, - MSG_MOVE_UNROOT = 0x0ED, - MSG_MOVE_HEARTBEAT = 0x0EE, - SMSG_MOVE_KNOCK_BACK = 0x0EF, - CMSG_MOVE_KNOCK_BACK_ACK = 0x0F0, - MSG_MOVE_KNOCK_BACK = 0x0F1, - SMSG_MOVE_FEATHER_FALL = 0x0F2, - SMSG_MOVE_NORMAL_FALL = 0x0F3, - SMSG_MOVE_SET_HOVER = 0x0F4, - SMSG_MOVE_UNSET_HOVER = 0x0F5, - CMSG_MOVE_HOVER_ACK = 0x0F6, - MSG_MOVE_HOVER = 0x0F7, - CMSG_TRIGGER_CINEMATIC_CHEAT = 0x0F8, - CMSG_OPENING_CINEMATIC = 0x0F9, - SMSG_TRIGGER_CINEMATIC = 0x0FA, - CMSG_NEXT_CINEMATIC_CAMERA = 0x0FB, - CMSG_COMPLETE_CINEMATIC = 0x0FC, - SMSG_TUTORIAL_FLAGS = 0x0FD, - CMSG_TUTORIAL_FLAG = 0x0FE, - CMSG_TUTORIAL_CLEAR = 0x0FF, - CMSG_TUTORIAL_RESET = 0x100, - CMSG_STANDSTATECHANGE = 0x101, - CMSG_EMOTE = 0x102, - SMSG_EMOTE = 0x103, - CMSG_TEXT_EMOTE = 0x104, - SMSG_TEXT_EMOTE = 0x105, - CMSG_AUTOEQUIP_GROUND_ITEM = 0x106, - CMSG_AUTOSTORE_GROUND_ITEM = 0x107, - CMSG_AUTOSTORE_LOOT_ITEM = 0x108, - CMSG_STORE_LOOT_IN_SLOT = 0x109, - CMSG_AUTOEQUIP_ITEM = 0x10A, - CMSG_AUTOSTORE_BAG_ITEM = 0x10B, - CMSG_SWAP_ITEM = 0x10C, - CMSG_SWAP_INV_ITEM = 0x10D, - CMSG_SPLIT_ITEM = 0x10E, - CMSG_AUTOEQUIP_ITEM_SLOT = 0x10F, - CMSG_UNCLAIM_LICENSE = 0x110, - CMSG_DESTROYITEM = 0x111, - SMSG_INVENTORY_CHANGE_FAILURE = 0x112, - SMSG_OPEN_CONTAINER = 0x113, - CMSG_INSPECT = 0x114, - SMSG_INSPECT_RESULTS_UPDATE = 0x115, - CMSG_INITIATE_TRADE = 0x116, - CMSG_BEGIN_TRADE = 0x117, - CMSG_BUSY_TRADE = 0x118, - CMSG_IGNORE_TRADE = 0x119, - CMSG_ACCEPT_TRADE = 0x11A, - CMSG_UNACCEPT_TRADE = 0x11B, - CMSG_CANCEL_TRADE = 0x11C, - CMSG_SET_TRADE_ITEM = 0x11D, - CMSG_CLEAR_TRADE_ITEM = 0x11E, - CMSG_SET_TRADE_GOLD = 0x11F, - SMSG_TRADE_STATUS = 0x120, - SMSG_TRADE_STATUS_EXTENDED = 0x121, - SMSG_INITIALIZE_FACTIONS = 0x122, - SMSG_SET_FACTION_VISIBLE = 0x123, - SMSG_SET_FACTION_STANDING = 0x124, - CMSG_SET_FACTION_ATWAR = 0x125, - CMSG_SET_FACTION_CHEAT = 0x126, - SMSG_SET_PROFICIENCY = 0x127, - CMSG_SET_ACTION_BUTTON = 0x128, - SMSG_ACTION_BUTTONS = 0x129, - SMSG_INITIAL_SPELLS = 0x12A, - SMSG_LEARNED_SPELL = 0x12B, - SMSG_SUPERCEDED_SPELL = 0x12C, - CMSG_NEW_SPELL_SLOT = 0x12D, - CMSG_CAST_SPELL = 0x12E, - CMSG_CANCEL_CAST = 0x12F, - SMSG_CAST_FAILED = 0x130, - SMSG_SPELL_START = 0x131, - SMSG_SPELL_GO = 0x132, - SMSG_SPELL_FAILURE = 0x133, - SMSG_SPELL_COOLDOWN = 0x134, - SMSG_COOLDOWN_EVENT = 0x135, - CMSG_CANCEL_AURA = 0x136, - SMSG_EQUIPMENT_SET_SAVED = 0x137, - SMSG_PET_CAST_FAILED = 0x138, - MSG_CHANNEL_START = 0x139, - MSG_CHANNEL_UPDATE = 0x13A, - CMSG_CANCEL_CHANNELLING = 0x13B, - SMSG_AI_REACTION = 0x13C, - CMSG_SET_SELECTION = 0x13D, - CMSG_DELETEEQUIPMENT_SET = 0x13E, - CMSG_INSTANCE_LOCK_RESPONSE = 0x13F, - CMSG_DEBUG_PASSIVE_AURA = 0x140, - CMSG_ATTACKSWING = 0x141, - CMSG_ATTACKSTOP = 0x142, - SMSG_ATTACKSTART = 0x143, - SMSG_ATTACKSTOP = 0x144, - SMSG_ATTACKSWING_NOTINRANGE = 0x145, - SMSG_ATTACKSWING_BADFACING = 0x146, - SMSG_INSTANCE_LOCK_WARNING_QUERY = 0x147, - SMSG_ATTACKSWING_DEADTARGET = 0x148, - SMSG_ATTACKSWING_CANT_ATTACK = 0x149, - SMSG_ATTACKERSTATEUPDATE = 0x14A, - SMSG_BATTLEFIELD_PORT_DENIED = 0x14B, - CMSG_PERFORM_ACTION_SET = 0x14C, - SMSG_RESUME_CAST_BAR = 0x14D, - SMSG_CANCEL_COMBAT = 0x14E, - SMSG_SPELLBREAKLOG = 0x14F, - SMSG_SPELLHEALLOG = 0x150, - SMSG_SPELLENERGIZELOG = 0x151, - SMSG_BREAK_TARGET = 0x152, - CMSG_SAVE_PLAYER = 0x153, - CMSG_SETDEATHBINDPOINT = 0x154, - SMSG_BINDPOINTUPDATE = 0x155, - CMSG_GETDEATHBINDZONE = 0x156, - SMSG_BINDZONEREPLY = 0x157, - SMSG_PLAYERBOUND = 0x158, - SMSG_CLIENT_CONTROL_UPDATE = 0x159, - CMSG_REPOP_REQUEST = 0x15A, - SMSG_RESURRECT_REQUEST = 0x15B, - CMSG_RESURRECT_RESPONSE = 0x15C, - CMSG_LOOT = 0x15D, - CMSG_LOOT_MONEY = 0x15E, - CMSG_LOOT_RELEASE = 0x15F, - SMSG_LOOT_RESPONSE = 0x160, - SMSG_LOOT_RELEASE_RESPONSE = 0x161, - SMSG_LOOT_REMOVED = 0x162, - SMSG_LOOT_MONEY_NOTIFY = 0x163, - SMSG_LOOT_ITEM_NOTIFY = 0x164, - SMSG_LOOT_CLEAR_MONEY = 0x165, - SMSG_ITEM_PUSH_RESULT = 0x166, - SMSG_DUEL_REQUESTED = 0x167, - SMSG_DUEL_OUTOFBOUNDS = 0x168, - SMSG_DUEL_INBOUNDS = 0x169, - SMSG_DUEL_COMPLETE = 0x16A, - SMSG_DUEL_WINNER = 0x16B, - CMSG_DUEL_ACCEPTED = 0x16C, - CMSG_DUEL_CANCELLED = 0x16D, - SMSG_MOUNTRESULT = 0x16E, - SMSG_DISMOUNTRESULT = 0x16F, - SMSG_REMOVED_FROM_PVP_QUEUE = 0x170, - CMSG_MOUNTSPECIAL_ANIM = 0x171, - SMSG_MOUNTSPECIAL_ANIM = 0x172, - SMSG_PET_TAME_FAILURE = 0x173, - CMSG_PET_SET_ACTION = 0x174, - CMSG_PET_ACTION = 0x175, - CMSG_PET_ABANDON = 0x176, - CMSG_PET_RENAME = 0x177, - SMSG_PET_NAME_INVALID = 0x178, - SMSG_PET_SPELLS = 0x179, - SMSG_PET_MODE = 0x17A, - CMSG_GOSSIP_HELLO = 0x17B, - CMSG_GOSSIP_SELECT_OPTION = 0x17C, - SMSG_GOSSIP_MESSAGE = 0x17D, - SMSG_GOSSIP_COMPLETE = 0x17E, - CMSG_NPC_TEXT_QUERY = 0x17F, - SMSG_NPC_TEXT_UPDATE = 0x180, - SMSG_NPC_WONT_TALK = 0x181, - CMSG_QUESTGIVER_STATUS_QUERY = 0x182, - SMSG_QUESTGIVER_STATUS = 0x183, - CMSG_QUESTGIVER_HELLO = 0x184, - SMSG_QUESTGIVER_QUEST_LIST = 0x185, - CMSG_QUESTGIVER_QUERY_QUEST = 0x186, - CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 0x187, - SMSG_QUESTGIVER_QUEST_DETAILS = 0x188, - CMSG_QUESTGIVER_ACCEPT_QUEST = 0x189, - CMSG_QUESTGIVER_COMPLETE_QUEST = 0x18A, - SMSG_QUESTGIVER_REQUEST_ITEMS = 0x18B, - CMSG_QUESTGIVER_REQUEST_REWARD = 0x18C, - SMSG_QUESTGIVER_OFFER_REWARD = 0x18D, - CMSG_QUESTGIVER_CHOOSE_REWARD = 0x18E, - SMSG_QUESTGIVER_QUEST_INVALID = 0x18F, - CMSG_QUESTGIVER_CANCEL = 0x190, - SMSG_QUESTGIVER_QUEST_COMPLETE = 0x191, - SMSG_QUESTGIVER_QUEST_FAILED = 0x192, - CMSG_QUESTLOG_SWAP_QUEST = 0x193, - CMSG_QUESTLOG_REMOVE_QUEST = 0x194, - SMSG_QUESTLOG_FULL = 0x195, - SMSG_QUESTUPDATE_FAILED = 0x196, - SMSG_QUESTUPDATE_FAILEDTIMER = 0x197, - SMSG_QUESTUPDATE_COMPLETE = 0x198, - SMSG_QUESTUPDATE_ADD_KILL = 0x199, - SMSG_QUESTUPDATE_ADD_ITEM = 0x19A, - CMSG_QUEST_CONFIRM_ACCEPT = 0x19B, - SMSG_QUEST_CONFIRM_ACCEPT = 0x19C, - CMSG_PUSHQUESTTOPARTY = 0x19D, - CMSG_LIST_INVENTORY = 0x19E, - SMSG_LIST_INVENTORY = 0x19F, - CMSG_SELL_ITEM = 0x1A0, - SMSG_SELL_ITEM = 0x1A1, - CMSG_BUY_ITEM = 0x1A2, - CMSG_BUY_ITEM_IN_SLOT = 0x1A3, - SMSG_BUY_ITEM = 0x1A4, - SMSG_BUY_FAILED = 0x1A5, - CMSG_TAXICLEARALLNODES = 0x1A6, - CMSG_TAXIENABLEALLNODES = 0x1A7, - CMSG_TAXISHOWNODES = 0x1A8, - SMSG_SHOWTAXINODES = 0x1A9, - CMSG_TAXINODE_STATUS_QUERY = 0x1AA, - SMSG_TAXINODE_STATUS = 0x1AB, - CMSG_TAXIQUERYAVAILABLENODES = 0x1AC, - CMSG_ACTIVATETAXI = 0x1AD, - SMSG_ACTIVATETAXIREPLY = 0x1AE, - SMSG_NEW_TAXI_PATH = 0x1AF, - CMSG_TRAINER_LIST = 0x1B0, - SMSG_TRAINER_LIST = 0x1B1, - CMSG_TRAINER_BUY_SPELL = 0x1B2, - SMSG_TRAINER_BUY_SUCCEEDED = 0x1B3, - SMSG_TRAINER_BUY_FAILED = 0x1B4, - CMSG_BINDER_ACTIVATE = 0x1B5, - SMSG_PLAYERBINDERROR = 0x1B6, - CMSG_BANKER_ACTIVATE = 0x1B7, - SMSG_SHOW_BANK = 0x1B8, - CMSG_BUY_BANK_SLOT = 0x1B9, - SMSG_BUY_BANK_SLOT_RESULT = 0x1BA, - CMSG_PETITION_SHOWLIST = 0x1BB, - SMSG_PETITION_SHOWLIST = 0x1BC, - CMSG_PETITION_BUY = 0x1BD, - CMSG_PETITION_SHOW_SIGNATURES = 0x1BE, - SMSG_PETITION_SHOW_SIGNATURES = 0x1BF, - CMSG_PETITION_SIGN = 0x1C0, - SMSG_PETITION_SIGN_RESULTS = 0x1C1, - MSG_PETITION_DECLINE = 0x1C2, - CMSG_OFFER_PETITION = 0x1C3, - CMSG_TURN_IN_PETITION = 0x1C4, - SMSG_TURN_IN_PETITION_RESULTS = 0x1C5, - CMSG_PETITION_QUERY = 0x1C6, - SMSG_PETITION_QUERY_RESPONSE = 0x1C7, - SMSG_FISH_NOT_HOOKED = 0x1C8, - SMSG_FISH_ESCAPED = 0x1C9, - CMSG_BUG = 0x1CA, - SMSG_NOTIFICATION = 0x1CB, - CMSG_PLAYED_TIME = 0x1CC, - SMSG_PLAYED_TIME = 0x1CD, - CMSG_QUERY_TIME = 0x1CE, - SMSG_QUERY_TIME_RESPONSE = 0x1CF, - SMSG_LOG_XPGAIN = 0x1D0, - SMSG_AURACASTLOG = 0x1D1, - CMSG_RECLAIM_CORPSE = 0x1D2, - CMSG_WRAP_ITEM = 0x1D3, - SMSG_LEVELUP_INFO = 0x1D4, - MSG_MINIMAP_PING = 0x1D5, - SMSG_RESISTLOG = 0x1D6, - SMSG_ENCHANTMENTLOG = 0x1D7, - CMSG_SET_SKILL_CHEAT = 0x1D8, - SMSG_START_MIRROR_TIMER = 0x1D9, - SMSG_PAUSE_MIRROR_TIMER = 0x1DA, - SMSG_STOP_MIRROR_TIMER = 0x1DB, - CMSG_PING = 0x1DC, - SMSG_PONG = 0x1DD, - SMSG_CLEAR_COOLDOWN = 0x1DE, - SMSG_GAMEOBJECT_PAGETEXT = 0x1DF, - CMSG_SETSHEATHED = 0x1E0, - SMSG_COOLDOWN_CHEAT = 0x1E1, - SMSG_SPELL_DELAYED = 0x1E2, - CMSG_QUEST_POI_QUERY = 0x1E3, - SMSG_QUEST_POI_QUERY_RESPONSE = 0x1E4, - CMSG_GHOST = 0x1E5, - CMSG_GM_INVIS = 0x1E6, - SMSG_INVALID_PROMOTION_CODE = 0x1E7, - MSG_GM_BIND_OTHER = 0x1E8, - MSG_GM_SUMMON = 0x1E9, - SMSG_ITEM_TIME_UPDATE = 0x1EA, - SMSG_ITEM_ENCHANT_TIME_UPDATE = 0x1EB, - SMSG_AUTH_CHALLENGE = 0x1EC, - CMSG_AUTH_SESSION = 0x1ED, - SMSG_AUTH_RESPONSE = 0x1EE, - MSG_GM_SHOWLABEL = 0x1EF, - CMSG_PET_CAST_SPELL = 0x1F0, - MSG_SAVE_GUILD_EMBLEM = 0x1F1, - MSG_TABARDVENDOR_ACTIVATE = 0x1F2, - SMSG_PLAY_SPELL_VISUAL = 0x1F3, - CMSG_ZONEUPDATE = 0x1F4, - SMSG_PARTYKILLLOG = 0x1F5, - SMSG_COMPRESSED_UPDATE_OBJECT = 0x1F6, - SMSG_PLAY_SPELL_IMPACT = 0x1F7, - SMSG_EXPLORATION_EXPERIENCE = 0x1F8, - CMSG_GM_SET_SECURITY_GROUP = 0x1F9, - CMSG_GM_NUKE = 0x1FA, - MSG_RANDOM_ROLL = 0x1FB, - SMSG_ENVIRONMENTALDAMAGELOG = 0x1FC, - CMSG_CHANGEPLAYER_DIFFICULTY = 0x1FD, - SMSG_RWHOIS = 0x1FE, - SMSG_LFG_PLAYER_REWARD = 0x1FF, // uint32, uint8, uint32, uint32, uint32, uint32, uint32, uint8, for (uint8) {uint32, uint32, uint32} - SMSG_LFG_TELEPORT_DENIED = 0x200, // uint32 (1, 2, 4, 6;0, 5, 7) - CMSG_UNLEARN_SPELL = 0x201, - CMSG_UNLEARN_SKILL = 0x202, - SMSG_REMOVED_SPELL = 0x203, - CMSG_DECHARGE = 0x204, - CMSG_GMTICKET_CREATE = 0x205, - SMSG_GMTICKET_CREATE = 0x206, - CMSG_GMTICKET_UPDATETEXT = 0x207, - SMSG_GMTICKET_UPDATETEXT = 0x208, - SMSG_ACCOUNT_DATA_TIMES = 0x209, - CMSG_REQUEST_ACCOUNT_DATA = 0x20A, - CMSG_UPDATE_ACCOUNT_DATA = 0x20B, - SMSG_UPDATE_ACCOUNT_DATA = 0x20C, - SMSG_CLEAR_FAR_SIGHT_IMMEDIATE = 0x20D, - SMSG_CHANGEPLAYER_DIFFICULTY_RESULT = 0x20E, - CMSG_GM_TEACH = 0x20F, - CMSG_GM_CREATE_ITEM_TARGET = 0x210, - CMSG_GMTICKET_GETTICKET = 0x211, - SMSG_GMTICKET_GETTICKET = 0x212, - CMSG_UNLEARN_TALENTS = 0x213, - SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT = 0x214, - SMSG_GAMEOBJECT_DESPAWN_ANIM = 0x215, - MSG_CORPSE_QUERY = 0x216, - CMSG_GMTICKET_DELETETICKET = 0x217, - SMSG_GMTICKET_DELETETICKET = 0x218, - SMSG_CHAT_WRONG_FACTION = 0x219, - CMSG_GMTICKET_SYSTEMSTATUS = 0x21A, - SMSG_GMTICKET_SYSTEMSTATUS = 0x21B, - CMSG_SPIRIT_HEALER_ACTIVATE = 0x21C, - CMSG_SET_STAT_CHEAT = 0x21D, - SMSG_QUEST_FORCE_REMOVE = 0x21E, // uint32 questid - CMSG_SKILL_BUY_STEP = 0x21F, - CMSG_SKILL_BUY_RANK = 0x220, - CMSG_XP_CHEAT = 0x221, - SMSG_SPIRIT_HEALER_CONFIRM = 0x222, - CMSG_CHARACTER_POINT_CHEAT = 0x223, - SMSG_GOSSIP_POI = 0x224, - CMSG_CHAT_IGNORED = 0x225, - CMSG_GM_VISION = 0x226, - CMSG_SERVER_COMMAND = 0x227, - CMSG_GM_SILENCE = 0x228, - CMSG_GM_REVEALTO = 0x229, - CMSG_GM_RESURRECT = 0x22A, - CMSG_GM_SUMMONMOB = 0x22B, - CMSG_GM_MOVECORPSE = 0x22C, - CMSG_GM_FREEZE = 0x22D, - CMSG_GM_UBERINVIS = 0x22E, - CMSG_GM_REQUEST_PLAYER_INFO = 0x22F, - SMSG_GM_PLAYER_INFO = 0x230, - CMSG_GUILD_RANK = 0x231, - CMSG_GUILD_ADD_RANK = 0x232, - CMSG_GUILD_DEL_RANK = 0x233, - CMSG_GUILD_SET_PUBLIC_NOTE = 0x234, - CMSG_GUILD_SET_OFFICER_NOTE = 0x235, - SMSG_LOGIN_VERIFY_WORLD = 0x236, - CMSG_CLEAR_EXPLORATION = 0x237, - CMSG_SEND_MAIL = 0x238, - SMSG_SEND_MAIL_RESULT = 0x239, - CMSG_GET_MAIL_LIST = 0x23A, - SMSG_MAIL_LIST_RESULT = 0x23B, - CMSG_BATTLEFIELD_LIST = 0x23C, - SMSG_BATTLEFIELD_LIST = 0x23D, - CMSG_BATTLEFIELD_JOIN = 0x23E, - SMSG_FORCE_SET_VEHICLE_REC_ID = 0x23F, - CMSG_SET_VEHICLE_REC_ID_ACK = 0x240, - CMSG_TAXICLEARNODE = 0x241, - CMSG_TAXIENABLENODE = 0x242, - CMSG_ITEM_TEXT_QUERY = 0x243, - SMSG_ITEM_TEXT_QUERY_RESPONSE = 0x244, - CMSG_MAIL_TAKE_MONEY = 0x245, - CMSG_MAIL_TAKE_ITEM = 0x246, - CMSG_MAIL_MARK_AS_READ = 0x247, - CMSG_MAIL_RETURN_TO_SENDER = 0x248, - CMSG_MAIL_DELETE = 0x249, - CMSG_MAIL_CREATE_TEXT_ITEM = 0x24A, - SMSG_SPELLLOGMISS = 0x24B, - SMSG_SPELLLOGEXECUTE = 0x24C, - SMSG_DEBUGAURAPROC = 0x24D, - SMSG_PERIODICAURALOG = 0x24E, - SMSG_SPELLDAMAGESHIELD = 0x24F, - SMSG_SPELLNONMELEEDAMAGELOG = 0x250, - CMSG_LEARN_TALENT = 0x251, - SMSG_RESURRECT_FAILED = 0x252, - CMSG_TOGGLE_PVP = 0x253, - SMSG_ZONE_UNDER_ATTACK = 0x254, - MSG_AUCTION_HELLO = 0x255, - CMSG_AUCTION_SELL_ITEM = 0x256, - CMSG_AUCTION_REMOVE_ITEM = 0x257, - CMSG_AUCTION_LIST_ITEMS = 0x258, - CMSG_AUCTION_LIST_OWNER_ITEMS = 0x259, - CMSG_AUCTION_PLACE_BID = 0x25A, - SMSG_AUCTION_COMMAND_RESULT = 0x25B, - SMSG_AUCTION_LIST_RESULT = 0x25C, - SMSG_AUCTION_OWNER_LIST_RESULT = 0x25D, - SMSG_AUCTION_BIDDER_NOTIFICATION = 0x25E, - SMSG_AUCTION_OWNER_NOTIFICATION = 0x25F, - SMSG_PROCRESIST = 0x260, - SMSG_COMBAT_EVENT_FAILED = 0x261, - SMSG_DISPEL_FAILED = 0x262, - SMSG_SPELLORDAMAGE_IMMUNE = 0x263, - CMSG_AUCTION_LIST_BIDDER_ITEMS = 0x264, - SMSG_AUCTION_BIDDER_LIST_RESULT = 0x265, - SMSG_SET_FLAT_SPELL_MODIFIER = 0x266, - SMSG_SET_PCT_SPELL_MODIFIER = 0x267, - CMSG_SET_AMMO = 0x268, - SMSG_CORPSE_RECLAIM_DELAY = 0x269, - CMSG_SET_ACTIVE_MOVER = 0x26A, - CMSG_PET_CANCEL_AURA = 0x26B, - CMSG_PLAYER_AI_CHEAT = 0x26C, - CMSG_CANCEL_AUTO_REPEAT_SPELL = 0x26D, - MSG_GM_ACCOUNT_ONLINE = 0x26E, - MSG_LIST_STABLED_PETS = 0x26F, - CMSG_STABLE_PET = 0x270, - CMSG_UNSTABLE_PET = 0x271, - CMSG_BUY_STABLE_SLOT = 0x272, - SMSG_STABLE_RESULT = 0x273, - CMSG_STABLE_REVIVE_PET = 0x274, - CMSG_STABLE_SWAP_PET = 0x275, - MSG_QUEST_PUSH_RESULT = 0x276, - SMSG_PLAY_MUSIC = 0x277, - SMSG_PLAY_OBJECT_SOUND = 0x278, - CMSG_REQUEST_PET_INFO = 0x279, - CMSG_FAR_SIGHT = 0x27A, - SMSG_SPELLDISPELLOG = 0x27B, - SMSG_DAMAGE_CALC_LOG = 0x27C, - CMSG_ENABLE_DAMAGE_LOG = 0x27D, - CMSG_GROUP_CHANGE_SUB_GROUP = 0x27E, - CMSG_REQUEST_PARTY_MEMBER_STATS = 0x27F, - CMSG_GROUP_SWAP_SUB_GROUP = 0x280, - CMSG_RESET_FACTION_CHEAT = 0x281, - CMSG_AUTOSTORE_BANK_ITEM = 0x282, - CMSG_AUTOBANK_ITEM = 0x283, - MSG_QUERY_NEXT_MAIL_TIME = 0x284, - SMSG_RECEIVED_MAIL = 0x285, - SMSG_RAID_GROUP_ONLY = 0x286, - CMSG_SET_DURABILITY_CHEAT = 0x287, - CMSG_SET_PVP_RANK_CHEAT = 0x288, - CMSG_ADD_PVP_MEDAL_CHEAT = 0x289, - CMSG_DEL_PVP_MEDAL_CHEAT = 0x28A, - CMSG_SET_PVP_TITLE = 0x28B, - SMSG_PVP_CREDIT = 0x28C, - SMSG_AUCTION_REMOVED_NOTIFICATION = 0x28D, - CMSG_GROUP_RAID_CONVERT = 0x28E, - CMSG_GROUP_ASSISTANT_LEADER = 0x28F, - CMSG_BUYBACK_ITEM = 0x290, - SMSG_SERVER_MESSAGE = 0x291, - CMSG_SET_SAVED_INSTANCE_EXTEND = 0x292, - SMSG_LFG_OFFER_CONTINUE = 0x293, - CMSG_TEST_DROP_RATE = 0x294, - SMSG_TEST_DROP_RATE_RESULT = 0x295, - CMSG_LFG_GET_STATUS = 0x296, - SMSG_SHOW_MAILBOX = 0x297, - SMSG_RESET_RANGED_COMBAT_TIMER = 0x298, - SMSG_CHAT_NOT_IN_PARTY = 0x299, // uint32, errors: ERR_NOT_IN_GROUP (2, 51) and ERR_NOT_IN_RAID (3, 39, 40) - CMSG_GMTICKETSYSTEM_TOGGLE = 0x29A, - CMSG_CANCEL_GROWTH_AURA = 0x29B, - SMSG_CANCEL_AUTO_REPEAT = 0x29C, - SMSG_STANDSTATE_UPDATE = 0x29D, - SMSG_LOOT_ALL_PASSED = 0x29E, - SMSG_LOOT_ROLL_WON = 0x29F, - CMSG_LOOT_ROLL = 0x2A0, - SMSG_LOOT_START_ROLL = 0x2A1, - SMSG_LOOT_ROLL = 0x2A2, - CMSG_LOOT_MASTER_GIVE = 0x2A3, - SMSG_LOOT_MASTER_LIST = 0x2A4, - SMSG_SET_FORCED_REACTIONS = 0x2A5, - SMSG_SPELL_FAILED_OTHER = 0x2A6, - SMSG_GAMEOBJECT_RESET_STATE = 0x2A7, - CMSG_REPAIR_ITEM = 0x2A8, - SMSG_CHAT_PLAYER_NOT_FOUND = 0x2A9, - MSG_TALENT_WIPE_CONFIRM = 0x2AA, - SMSG_SUMMON_REQUEST = 0x2AB, - CMSG_SUMMON_RESPONSE = 0x2AC, - MSG_DEV_SHOWLABEL = 0x2AD, - SMSG_MONSTER_MOVE_TRANSPORT = 0x2AE, - SMSG_PET_BROKEN = 0x2AF, - MSG_MOVE_FEATHER_FALL = 0x2B0, - MSG_MOVE_WATER_WALK = 0x2B1, - CMSG_SERVER_BROADCAST = 0x2B2, - CMSG_SELF_RES = 0x2B3, - SMSG_FEIGN_DEATH_RESISTED = 0x2B4, - CMSG_RUN_SCRIPT = 0x2B5, - SMSG_SCRIPT_MESSAGE = 0x2B6, - SMSG_DUEL_COUNTDOWN = 0x2B7, - SMSG_AREA_TRIGGER_MESSAGE = 0x2B8, - CMSG_SHOWING_HELM = 0x2B9, - CMSG_SHOWING_CLOAK = 0x2BA, - SMSG_LFG_ROLE_CHOSEN = 0x2BB, - SMSG_PLAYER_SKINNED = 0x2BC, - SMSG_DURABILITY_DAMAGE_DEATH = 0x2BD, - CMSG_SET_EXPLORATION = 0x2BE, - CMSG_SET_ACTIONBAR_TOGGLES = 0x2BF, - UMSG_DELETE_GUILD_CHARTER = 0x2C0, - MSG_PETITION_RENAME = 0x2C1, - SMSG_INIT_WORLD_STATES = 0x2C2, - SMSG_UPDATE_WORLD_STATE = 0x2C3, - CMSG_ITEM_NAME_QUERY = 0x2C4, - SMSG_ITEM_NAME_QUERY_RESPONSE = 0x2C5, - SMSG_PET_ACTION_FEEDBACK = 0x2C6, - CMSG_CHAR_RENAME = 0x2C7, - SMSG_CHAR_RENAME = 0x2C8, - CMSG_MOVE_SPLINE_DONE = 0x2C9, - CMSG_MOVE_FALL_RESET = 0x2CA, - SMSG_INSTANCE_SAVE_CREATED = 0x2CB, - SMSG_RAID_INSTANCE_INFO = 0x2CC, - CMSG_REQUEST_RAID_INFO = 0x2CD, - CMSG_MOVE_TIME_SKIPPED = 0x2CE, - CMSG_MOVE_FEATHER_FALL_ACK = 0x2CF, - CMSG_MOVE_WATER_WALK_ACK = 0x2D0, - CMSG_MOVE_NOT_ACTIVE_MOVER = 0x2D1, - SMSG_PLAY_SOUND = 0x2D2, - CMSG_BATTLEFIELD_STATUS = 0x2D3, - SMSG_BATTLEFIELD_STATUS = 0x2D4, - CMSG_BATTLEFIELD_PORT = 0x2D5, - MSG_INSPECT_HONOR_STATS = 0x2D6, - CMSG_BATTLEMASTER_HELLO = 0x2D7, - CMSG_MOVE_START_SWIM_CHEAT = 0x2D8, - CMSG_MOVE_STOP_SWIM_CHEAT = 0x2D9, - SMSG_FORCE_WALK_SPEED_CHANGE = 0x2DA, - CMSG_FORCE_WALK_SPEED_CHANGE_ACK = 0x2DB, - SMSG_FORCE_SWIM_BACK_SPEED_CHANGE = 0x2DC, - CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK = 0x2DD, - SMSG_FORCE_TURN_RATE_CHANGE = 0x2DE, - CMSG_FORCE_TURN_RATE_CHANGE_ACK = 0x2DF, - MSG_PVP_LOG_DATA = 0x2E0, - CMSG_LEAVE_BATTLEFIELD = 0x2E1, - CMSG_AREA_SPIRIT_HEALER_QUERY = 0x2E2, - CMSG_AREA_SPIRIT_HEALER_QUEUE = 0x2E3, - SMSG_AREA_SPIRIT_HEALER_TIME = 0x2E4, - CMSG_GM_UNTEACH = 0x2E5, - SMSG_WARDEN_DATA = 0x2E6, - CMSG_WARDEN_DATA = 0x2E7, - SMSG_GROUP_JOINED_BATTLEGROUND = 0x2E8, - MSG_BATTLEGROUND_PLAYER_POSITIONS = 0x2E9, - CMSG_PET_STOP_ATTACK = 0x2EA, - SMSG_BINDER_CONFIRM = 0x2EB, - SMSG_BATTLEGROUND_PLAYER_JOINED = 0x2EC, - SMSG_BATTLEGROUND_PLAYER_LEFT = 0x2ED, - CMSG_BATTLEMASTER_JOIN = 0x2EE, - SMSG_ADDON_INFO = 0x2EF, - CMSG_PET_UNLEARN = 0x2F0, // Deprecated 3.x - SMSG_PET_UNLEARN_CONFIRM = 0x2F1, // Deprecated 3.x - SMSG_PARTY_MEMBER_STATS_FULL = 0x2F2, - CMSG_PET_SPELL_AUTOCAST = 0x2F3, - SMSG_WEATHER = 0x2F4, - SMSG_PLAY_TIME_WARNING = 0x2F5, - SMSG_MINIGAME_SETUP = 0x2F6, - SMSG_MINIGAME_STATE = 0x2F7, - CMSG_MINIGAME_MOVE = 0x2F8, - SMSG_MINIGAME_MOVE_FAILED = 0x2F9, - SMSG_RAID_INSTANCE_MESSAGE = 0x2FA, - SMSG_COMPRESSED_MOVES = 0x2FB, - CMSG_GUILD_INFO_TEXT = 0x2FC, - SMSG_CHAT_RESTRICTED = 0x2FD, - SMSG_SPLINE_SET_RUN_SPEED = 0x2FE, - SMSG_SPLINE_SET_RUN_BACK_SPEED = 0x2FF, - SMSG_SPLINE_SET_SWIM_SPEED = 0x300, - SMSG_SPLINE_SET_WALK_SPEED = 0x301, - SMSG_SPLINE_SET_SWIM_BACK_SPEED = 0x302, - SMSG_SPLINE_SET_TURN_RATE = 0x303, - SMSG_SPLINE_MOVE_UNROOT = 0x304, - SMSG_SPLINE_MOVE_FEATHER_FALL = 0x305, - SMSG_SPLINE_MOVE_NORMAL_FALL = 0x306, - SMSG_SPLINE_MOVE_SET_HOVER = 0x307, - SMSG_SPLINE_MOVE_UNSET_HOVER = 0x308, - SMSG_SPLINE_MOVE_WATER_WALK = 0x309, - SMSG_SPLINE_MOVE_LAND_WALK = 0x30A, - SMSG_SPLINE_MOVE_START_SWIM = 0x30B, - SMSG_SPLINE_MOVE_STOP_SWIM = 0x30C, - SMSG_SPLINE_MOVE_SET_RUN_MODE = 0x30D, - SMSG_SPLINE_MOVE_SET_WALK_MODE = 0x30E, - CMSG_GM_NUKE_ACCOUNT = 0x30F, - MSG_GM_DESTROY_CORPSE = 0x310, - CMSG_GM_DESTROY_ONLINE_CORPSE = 0x311, - CMSG_ACTIVATETAXIEXPRESS = 0x312, - SMSG_SET_FACTION_ATWAR = 0x313, - SMSG_GAMETIMEBIAS_SET = 0x314, - CMSG_DEBUG_ACTIONS_START = 0x315, - CMSG_DEBUG_ACTIONS_STOP = 0x316, - CMSG_SET_FACTION_INACTIVE = 0x317, - CMSG_SET_WATCHED_FACTION = 0x318, - MSG_MOVE_TIME_SKIPPED = 0x319, - SMSG_SPLINE_MOVE_ROOT = 0x31A, - CMSG_SET_EXPLORATION_ALL = 0x31B, - SMSG_INVALIDATE_PLAYER = 0x31C, - CMSG_RESET_INSTANCES = 0x31D, - SMSG_INSTANCE_RESET = 0x31E, - SMSG_INSTANCE_RESET_FAILED = 0x31F, - SMSG_UPDATE_LAST_INSTANCE = 0x320, - MSG_RAID_TARGET_UPDATE = 0x321, - MSG_RAID_READY_CHECK = 0x322, - CMSG_LUA_USAGE = 0x323, - SMSG_PET_ACTION_SOUND = 0x324, - SMSG_PET_DISMISS_SOUND = 0x325, - SMSG_GHOSTEE_GONE = 0x326, - CMSG_GM_UPDATE_TICKET_STATUS = 0x327, - SMSG_GM_TICKET_STATUS_UPDATE = 0x328, - MSG_SET_DUNGEON_DIFFICULTY = 0x329, - CMSG_GMSURVEY_SUBMIT = 0x32A, - SMSG_UPDATE_INSTANCE_OWNERSHIP = 0x32B, - CMSG_IGNORE_KNOCKBACK_CHEAT = 0x32C, - SMSG_CHAT_PLAYER_AMBIGUOUS = 0x32D, - MSG_DELAY_GHOST_TELEPORT = 0x32E, - SMSG_SPELLINSTAKILLLOG = 0x32F, - SMSG_SPELL_UPDATE_CHAIN_TARGETS = 0x330, - CMSG_CHAT_FILTERED = 0x331, - SMSG_EXPECTED_SPAM_RECORDS = 0x332, - SMSG_SPELLSTEALLOG = 0x333, - CMSG_LOTTERY_QUERY_OBSOLETE = 0x334, - SMSG_LOTTERY_QUERY_RESULT_OBSOLETE = 0x335, - CMSG_BUY_LOTTERY_TICKET_OBSOLETE = 0x336, - SMSG_LOTTERY_RESULT_OBSOLETE = 0x337, - SMSG_CHARACTER_PROFILE = 0x338, - SMSG_CHARACTER_PROFILE_REALM_CONNECTED = 0x339, - SMSG_DEFENSE_MESSAGE = 0x33A, - SMSG_INSTANCE_DIFFICULTY = 0x33B, - MSG_GM_RESETINSTANCELIMIT = 0x33C, - SMSG_MOTD = 0x33D, - SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY= 0x33E, - SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY= 0x33F, - CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK= 0x340, - MSG_MOVE_START_SWIM_CHEAT = 0x341, - MSG_MOVE_STOP_SWIM_CHEAT = 0x342, - SMSG_MOVE_SET_CAN_FLY = 0x343, - SMSG_MOVE_UNSET_CAN_FLY = 0x344, - CMSG_MOVE_SET_CAN_FLY_ACK = 0x345, - CMSG_MOVE_SET_FLY = 0x346, - CMSG_SOCKET_GEMS = 0x347, - CMSG_ARENA_TEAM_CREATE = 0x348, - SMSG_ARENA_TEAM_COMMAND_RESULT = 0x349, - MSG_MOVE_UPDATE_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY= 0x34A, - CMSG_ARENA_TEAM_QUERY = 0x34B, - SMSG_ARENA_TEAM_QUERY_RESPONSE = 0x34C, - CMSG_ARENA_TEAM_ROSTER = 0x34D, - SMSG_ARENA_TEAM_ROSTER = 0x34E, - CMSG_ARENA_TEAM_INVITE = 0x34F, - SMSG_ARENA_TEAM_INVITE = 0x350, - CMSG_ARENA_TEAM_ACCEPT = 0x351, - CMSG_ARENA_TEAM_DECLINE = 0x352, - CMSG_ARENA_TEAM_LEAVE = 0x353, - CMSG_ARENA_TEAM_REMOVE = 0x354, - CMSG_ARENA_TEAM_DISBAND = 0x355, - CMSG_ARENA_TEAM_LEADER = 0x356, - SMSG_ARENA_TEAM_EVENT = 0x357, - CMSG_BATTLEMASTER_JOIN_ARENA = 0x358, - MSG_MOVE_START_ASCEND = 0x359, - MSG_MOVE_STOP_ASCEND = 0x35A, - SMSG_ARENA_TEAM_STATS = 0x35B, - CMSG_LFG_JOIN = 0x35C, - CMSG_LFG_LEAVE = 0x35D, - CMSG_SEARCH_LFG_JOIN = 0x35E, - CMSG_SEARCH_LFG_LEAVE = 0x35F, - SMSG_UPDATE_LFG_LIST = 0x360, // uint32, uint32, if (uint8) { uint32 count, for (count) { uint64} }, uint32 count2, uint32, for (count2) { uint64, uint32 flags, if (flags & 0x2) {string}, if (flags & 0x10) {for (3) uint8}, if (flags & 0x80) {uint64, uint32}}, uint32 count3, uint32, for (count3) {uint64, uint32 flags, if (flags & 0x1) {uint8, uint8, uint8, for (3) uint8, uint32, uint32, uint32, uint32, uint32, uint32, float, float, uint32, uint32, uint32, uint32, uint32, float, uint32, uint32, uint32, uint32, uint32, uint32}, if (flags&0x2) string, if (flags&0x4) uint8, if (flags&0x8) uint64, if (flags&0x10) uint8, if (flags&0x20) uint32, if (flags&0x40) uint8, if (flags& 0x80) {uint64, uint32}} - SMSG_LFG_PROPOSAL_UPDATE = 0x361, // uint32, uint8, uint32, uint32, uint8, for (uint8) {uint32, uint8, uint8, uint8, uint8} - CMSG_LFG_PROPOSAL_RESULT = 0x362, - SMSG_LFG_ROLE_CHECK_UPDATE = 0x363, // uint32, uint8, for (uint8) uint32, uint8, for (uint8) { uint64, uint8, uint32, uint8, } - SMSG_LFG_JOIN_RESULT = 0x364, // uint32 unk, uint32, if (unk == 6) { uint8 count, for (count) uint64 } - SMSG_LFG_QUEUE_STATUS = 0x365, // uint32 dungeon, uint32 lfgtype, uint32, uint32, uint32, uint32, uint8, uint8, uint8, uint8 - CMSG_SET_LFG_COMMENT = 0x366, - SMSG_LFG_UPDATE_PLAYER = 0x367, // uint8, if (uint8) { uint8, uint8, uint8, uint8, if (uint8) for (uint8) uint32, string} - SMSG_LFG_UPDATE_PARTY = 0x368, // uint8, if (uint8) { uint8, uint8, uint8, for (3) uint8, uint8, if (uint8) for (uint8) uint32, string} - SMSG_LFG_UPDATE_SEARCH = 0x369, // uint8 - CMSG_LFG_SET_ROLES = 0x36A, - CMSG_LFG_SET_NEEDS = 0x36B, - CMSG_LFG_SET_BOOT_VOTE = 0x36C, - SMSG_LFG_BOOT_PROPOSAL_UPDATE = 0x36D, // uint8, uint8, uint8, uint64, uint32, uint32, uint32, uint32 - CMSG_LFD_PLAYER_LOCK_INFO_REQUEST = 0x36E, - SMSG_LFG_PLAYER_INFO = 0x36F, // uint8, for (uint8) { uint32, uint8, uint32, uint32, uint32, uint32, uint8, for (uint8) {uint32, uint32, uint32}}, uint32, for (uint32) {uint32, uint32} - CMSG_LFG_TELEPORT = 0x370, - CMSG_LFD_PARTY_LOCK_INFO_REQUEST = 0x371, - SMSG_LFG_PARTY_INFO = 0x372, // uint8, for (uint8) uint64 - SMSG_TITLE_EARNED = 0x373, - CMSG_SET_TITLE = 0x374, - CMSG_CANCEL_MOUNT_AURA = 0x375, - SMSG_ARENA_ERROR = 0x376, - MSG_INSPECT_ARENA_TEAMS = 0x377, - SMSG_DEATH_RELEASE_LOC = 0x378, - CMSG_CANCEL_TEMP_ENCHANTMENT = 0x379, - SMSG_FORCED_DEATH_UPDATE = 0x37A, - CMSG_CHEAT_SET_HONOR_CURRENCY = 0x37B, - CMSG_CHEAT_SET_ARENA_CURRENCY = 0x37C, - MSG_MOVE_SET_FLIGHT_SPEED_CHEAT = 0x37D, - MSG_MOVE_SET_FLIGHT_SPEED = 0x37E, - MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT = 0x37F, - MSG_MOVE_SET_FLIGHT_BACK_SPEED = 0x380, - SMSG_FORCE_FLIGHT_SPEED_CHANGE = 0x381, - CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK = 0x382, - SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE = 0x383, - CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK = 0x384, - SMSG_SPLINE_SET_FLIGHT_SPEED = 0x385, - SMSG_SPLINE_SET_FLIGHT_BACK_SPEED = 0x386, - CMSG_MAELSTROM_INVALIDATE_CACHE = 0x387, - SMSG_FLIGHT_SPLINE_SYNC = 0x388, - CMSG_SET_TAXI_BENCHMARK_MODE = 0x389, - SMSG_JOINED_BATTLEGROUND_QUEUE = 0x38A, - SMSG_REALM_SPLIT = 0x38B, - CMSG_REALM_SPLIT = 0x38C, - CMSG_MOVE_CHNG_TRANSPORT = 0x38D, - MSG_PARTY_ASSIGNMENT = 0x38E, - SMSG_OFFER_PETITION_ERROR = 0x38F, - SMSG_TIME_SYNC_REQ = 0x390, - CMSG_TIME_SYNC_RESP = 0x391, - CMSG_SEND_LOCAL_EVENT = 0x392, - CMSG_SEND_GENERAL_TRIGGER = 0x393, - CMSG_SEND_COMBAT_TRIGGER = 0x394, - CMSG_MAELSTROM_GM_SENT_MAIL = 0x395, - SMSG_RESET_FAILED_NOTIFY = 0x396, - SMSG_REAL_GROUP_UPDATE = 0x397, - SMSG_LFG_DISABLED = 0x398, - CMSG_ACTIVE_PVP_CHEAT = 0x399, - CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY = 0x39A, - SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE = 0x39B, - SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE = 0x39C, - SMSG_UPDATE_COMBO_POINTS = 0x39D, - SMSG_VOICE_SESSION_ROSTER_UPDATE = 0x39E, - SMSG_VOICE_SESSION_LEAVE = 0x39F, - SMSG_VOICE_SESSION_ADJUST_PRIORITY = 0x3A0, - CMSG_VOICE_SET_TALKER_MUTED_REQUEST = 0x3A1, - SMSG_VOICE_SET_TALKER_MUTED = 0x3A2, - SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE = 0x3A3, - SMSG_SET_EXTRA_AURA_INFO_OBSOLETE = 0x3A4, - SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE = 0x3A5, - SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE = 0x3A6, - MSG_MOVE_START_DESCEND = 0x3A7, - CMSG_IGNORE_REQUIREMENTS_CHEAT = 0x3A8, - SMSG_IGNORE_REQUIREMENTS_CHEAT = 0x3A9, - SMSG_SPELL_CHANCE_PROC_LOG = 0x3AA, - CMSG_MOVE_SET_RUN_SPEED = 0x3AB, - SMSG_DISMOUNT = 0x3AC, - MSG_MOVE_UPDATE_CAN_FLY = 0x3AD, - MSG_RAID_READY_CHECK_CONFIRM = 0x3AE, - CMSG_VOICE_SESSION_ENABLE = 0x3AF, - SMSG_VOICE_SESSION_ENABLE = 0x3B0, - SMSG_VOICE_PARENTAL_CONTROLS = 0x3B1, - CMSG_GM_WHISPER = 0x3B2, - SMSG_GM_MESSAGECHAT = 0x3B3, - MSG_GM_GEARRATING = 0x3B4, - CMSG_COMMENTATOR_ENABLE = 0x3B5, - SMSG_COMMENTATOR_STATE_CHANGED = 0x3B6, - CMSG_COMMENTATOR_GET_MAP_INFO = 0x3B7, - SMSG_COMMENTATOR_MAP_INFO = 0x3B8, - CMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3B9, - SMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3BA, - SMSG_COMMENTATOR_PLAYER_INFO = 0x3BB, - CMSG_COMMENTATOR_ENTER_INSTANCE = 0x3BC, - CMSG_COMMENTATOR_EXIT_INSTANCE = 0x3BD, - CMSG_COMMENTATOR_INSTANCE_COMMAND = 0x3BE, - SMSG_CLEAR_TARGET = 0x3BF, - CMSG_BOT_DETECTED = 0x3C0, - SMSG_CROSSED_INEBRIATION_THRESHOLD = 0x3C1, - CMSG_CHEAT_PLAYER_LOGIN = 0x3C2, - CMSG_CHEAT_PLAYER_LOOKUP = 0x3C3, - SMSG_CHEAT_PLAYER_LOOKUP = 0x3C4, - SMSG_KICK_REASON = 0x3C5, - MSG_RAID_READY_CHECK_FINISHED = 0x3C6, - CMSG_COMPLAIN = 0x3C7, - SMSG_COMPLAIN_RESULT = 0x3C8, - SMSG_FEATURE_SYSTEM_STATUS = 0x3C9, - CMSG_GM_SHOW_COMPLAINTS = 0x3CA, - CMSG_GM_UNSQUELCH = 0x3CB, - CMSG_CHANNEL_SILENCE_VOICE = 0x3CC, - CMSG_CHANNEL_SILENCE_ALL = 0x3CD, - CMSG_CHANNEL_UNSILENCE_VOICE = 0x3CE, - CMSG_CHANNEL_UNSILENCE_ALL = 0x3CF, - CMSG_TARGET_CAST = 0x3D0, - CMSG_TARGET_SCRIPT_CAST = 0x3D1, - CMSG_CHANNEL_DISPLAY_LIST = 0x3D2, - CMSG_SET_ACTIVE_VOICE_CHANNEL = 0x3D3, - CMSG_GET_CHANNEL_MEMBER_COUNT = 0x3D4, - SMSG_CHANNEL_MEMBER_COUNT = 0x3D5, - CMSG_CHANNEL_VOICE_ON = 0x3D6, - CMSG_CHANNEL_VOICE_OFF = 0x3D7, - CMSG_DEBUG_LIST_TARGETS = 0x3D8, - SMSG_DEBUG_LIST_TARGETS = 0x3D9, - SMSG_AVAILABLE_VOICE_CHANNEL = 0x3DA, - CMSG_ADD_VOICE_IGNORE = 0x3DB, - CMSG_DEL_VOICE_IGNORE = 0x3DC, - CMSG_PARTY_SILENCE = 0x3DD, - CMSG_PARTY_UNSILENCE = 0x3DE, - MSG_NOTIFY_PARTY_SQUELCH = 0x3DF, - SMSG_COMSAT_RECONNECT_TRY = 0x3E0, - SMSG_COMSAT_DISCONNECT = 0x3E1, - SMSG_COMSAT_CONNECT_FAIL = 0x3E2, - SMSG_VOICE_CHAT_STATUS = 0x3E3, - CMSG_REPORT_PVP_AFK = 0x3E4, - SMSG_REPORT_PVP_AFK_RESULT = 0x3E5, - CMSG_GUILD_BANKER_ACTIVATE = 0x3E6, - CMSG_GUILD_BANK_QUERY_TAB = 0x3E7, - SMSG_GUILD_BANK_LIST = 0x3E8, - CMSG_GUILD_BANK_SWAP_ITEMS = 0x3E9, - CMSG_GUILD_BANK_BUY_TAB = 0x3EA, - CMSG_GUILD_BANK_UPDATE_TAB = 0x3EB, - CMSG_GUILD_BANK_DEPOSIT_MONEY = 0x3EC, - CMSG_GUILD_BANK_WITHDRAW_MONEY = 0x3ED, - MSG_GUILD_BANK_LOG_QUERY = 0x3EE, - CMSG_SET_CHANNEL_WATCH = 0x3EF, - SMSG_USERLIST_ADD = 0x3F0, - SMSG_USERLIST_REMOVE = 0x3F1, - SMSG_USERLIST_UPDATE = 0x3F2, - CMSG_CLEAR_CHANNEL_WATCH = 0x3F3, - SMSG_INSPECT_TALENT = 0x3F4, - SMSG_GOGOGO_OBSOLETE = 0x3F5, - SMSG_ECHO_PARTY_SQUELCH = 0x3F6, - CMSG_SET_TITLE_SUFFIX = 0x3F7, - CMSG_SPELLCLICK = 0x3F8, - SMSG_LOOT_LIST = 0x3F9, - CMSG_GM_CHARACTER_RESTORE = 0x3FA, - CMSG_GM_CHARACTER_SAVE = 0x3FB, - SMSG_VOICESESSION_FULL = 0x3FC, - MSG_GUILD_PERMISSIONS = 0x3FD, - MSG_GUILD_BANK_MONEY_WITHDRAWN = 0x3FE, - MSG_GUILD_EVENT_LOG_QUERY = 0x3FF, - CMSG_MAELSTROM_RENAME_GUILD = 0x400, - CMSG_GET_MIRRORIMAGE_DATA = 0x401, - SMSG_MIRRORIMAGE_DATA = 0x402, - SMSG_FORCE_DISPLAY_UPDATE = 0x403, - SMSG_SPELL_CHANCE_RESIST_PUSHBACK = 0x404, - CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x405, - SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x406, - CMSG_KEEP_ALIVE = 0x407, - SMSG_RAID_READY_CHECK_ERROR = 0x408, - CMSG_OPT_OUT_OF_LOOT = 0x409, - MSG_QUERY_GUILD_BANK_TEXT = 0x40A, - CMSG_SET_GUILD_BANK_TEXT = 0x40B, - CMSG_SET_GRANTABLE_LEVELS = 0x40C, - CMSG_GRANT_LEVEL = 0x40D, - CMSG_REFER_A_FRIEND = 0x40E, - MSG_GM_CHANGE_ARENA_RATING = 0x40F, - CMSG_DECLINE_CHANNEL_INVITE = 0x410, - SMSG_GROUPACTION_THROTTLED = 0x411, - SMSG_OVERRIDE_LIGHT = 0x412, // uint32 defaultMapLight, uint32 overrideLight, uint32 transitionTimeMs - SMSG_TOTEM_CREATED = 0x413, - CMSG_TOTEM_DESTROYED = 0x414, - CMSG_EXPIRE_RAID_INSTANCE = 0x415, - CMSG_NO_SPELL_VARIANCE = 0x416, - CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x417, - SMSG_QUESTGIVER_STATUS_MULTIPLE = 0x418, - CMSG_SET_PLAYER_DECLINED_NAMES = 0x419, - SMSG_SET_PLAYER_DECLINED_NAMES_RESULT = 0x41A, - CMSG_QUERY_SERVER_BUCK_DATA = 0x41B, - CMSG_CLEAR_SERVER_BUCK_DATA = 0x41C, - SMSG_SERVER_BUCK_DATA = 0x41D, - SMSG_SEND_UNLEARN_SPELLS = 0x41E, - SMSG_PROPOSE_LEVEL_GRANT = 0x41F, - CMSG_ACCEPT_LEVEL_GRANT = 0x420, - SMSG_REFER_A_FRIEND_FAILURE = 0x421, - SMSG_SPLINE_MOVE_SET_FLYING = 0x422, - SMSG_SPLINE_MOVE_UNSET_FLYING = 0x423, - SMSG_SUMMON_CANCEL = 0x424, - CMSG_CHANGE_PERSONAL_ARENA_RATING = 0x425, - CMSG_ALTER_APPEARANCE = 0x426, - SMSG_ENABLE_BARBER_SHOP = 0x427, - SMSG_BARBER_SHOP_RESULT = 0x428, - CMSG_CALENDAR_GET_CALENDAR = 0x429, - CMSG_CALENDAR_GET_EVENT = 0x42A, - CMSG_CALENDAR_GUILD_FILTER = 0x42B, - CMSG_CALENDAR_ARENA_TEAM = 0x42C, - CMSG_CALENDAR_ADD_EVENT = 0x42D, - CMSG_CALENDAR_UPDATE_EVENT = 0x42E, - CMSG_CALENDAR_REMOVE_EVENT = 0x42F, - CMSG_CALENDAR_COPY_EVENT = 0x430, - CMSG_CALENDAR_EVENT_INVITE = 0x431, - CMSG_CALENDAR_EVENT_RSVP = 0x432, - CMSG_CALENDAR_EVENT_REMOVE_INVITE = 0x433, - CMSG_CALENDAR_EVENT_STATUS = 0x434, - CMSG_CALENDAR_EVENT_MODERATOR_STATUS = 0x435, - SMSG_CALENDAR_SEND_CALENDAR = 0x436, - SMSG_CALENDAR_SEND_EVENT = 0x437, - SMSG_CALENDAR_FILTER_GUILD = 0x438, - SMSG_CALENDAR_ARENA_TEAM = 0x439, - SMSG_CALENDAR_EVENT_INVITE = 0x43A, - SMSG_CALENDAR_EVENT_INVITE_REMOVED = 0x43B, - SMSG_CALENDAR_EVENT_STATUS = 0x43C, - SMSG_CALENDAR_COMMAND_RESULT = 0x43D, - SMSG_CALENDAR_RAID_LOCKOUT_ADDED = 0x43E, - SMSG_CALENDAR_RAID_LOCKOUT_REMOVED = 0x43F, - SMSG_CALENDAR_EVENT_INVITE_ALERT = 0x440, - SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT = 0x441, - SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT = 0x442, - SMSG_CALENDAR_EVENT_REMOVED_ALERT = 0x443, - SMSG_CALENDAR_EVENT_UPDATED_ALERT = 0x444, - SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT = 0x445, - CMSG_CALENDAR_COMPLAIN = 0x446, - CMSG_CALENDAR_GET_NUM_PENDING = 0x447, - SMSG_CALENDAR_SEND_NUM_PENDING = 0x448, - CMSG_SAVE_DANCE = 0x449, - SMSG_NOTIFY_DANCE = 0x44A, - CMSG_PLAY_DANCE = 0x44B, - SMSG_PLAY_DANCE = 0x44C, - CMSG_LOAD_DANCES = 0x44D, - CMSG_STOP_DANCE = 0x44E, - SMSG_STOP_DANCE = 0x44F, - CMSG_SYNC_DANCE = 0x450, - CMSG_DANCE_QUERY = 0x451, - SMSG_DANCE_QUERY_RESPONSE = 0x452, - SMSG_INVALIDATE_DANCE = 0x453, - CMSG_DELETE_DANCE = 0x454, - SMSG_LEARNED_DANCE_MOVES = 0x455, - CMSG_LEARN_DANCE_MOVE = 0x456, - CMSG_UNLEARN_DANCE_MOVE = 0x457, - CMSG_SET_RUNE_COUNT = 0x458, - CMSG_SET_RUNE_COOLDOWN = 0x459, - MSG_MOVE_SET_PITCH_RATE_CHEAT = 0x45A, - MSG_MOVE_SET_PITCH_RATE = 0x45B, - SMSG_FORCE_PITCH_RATE_CHANGE = 0x45C, - CMSG_FORCE_PITCH_RATE_CHANGE_ACK = 0x45D, - SMSG_SPLINE_SET_PITCH_RATE = 0x45E, - CMSG_CALENDAR_EVENT_INVITE_NOTES = 0x45F, - SMSG_CALENDAR_EVENT_INVITE_NOTES = 0x460, - SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT = 0x461, - CMSG_UPDATE_MISSILE_TRAJECTORY = 0x462, - SMSG_UPDATE_ACCOUNT_DATA_COMPLETE = 0x463, - SMSG_TRIGGER_MOVIE = 0x464, - CMSG_COMPLETE_MOVIE = 0x465, - CMSG_SET_GLYPH_SLOT = 0x466, - CMSG_SET_GLYPH = 0x467, - SMSG_ACHIEVEMENT_EARNED = 0x468, - SMSG_DYNAMIC_DROP_ROLL_RESULT = 0x469, - SMSG_CRITERIA_UPDATE = 0x46A, - CMSG_QUERY_INSPECT_ACHIEVEMENTS = 0x46B, - SMSG_RESPOND_INSPECT_ACHIEVEMENTS = 0x46C, - CMSG_DISMISS_CONTROLLED_VEHICLE = 0x46D, - CMSG_COMPLETE_ACHIEVEMENT_CHEAT = 0x46E, - SMSG_QUESTUPDATE_ADD_PVP_KILL = 0x46F, - CMSG_SET_CRITERIA_CHEAT = 0x470, - SMSG_CALENDAR_RAID_LOCKOUT_UPDATED = 0x471, - CMSG_UNITANIMTIER_CHEAT = 0x472, - CMSG_CHAR_CUSTOMIZE = 0x473, - SMSG_CHAR_CUSTOMIZE = 0x474, - SMSG_PET_RENAMEABLE = 0x475, - CMSG_REQUEST_VEHICLE_EXIT = 0x476, - CMSG_REQUEST_VEHICLE_PREV_SEAT = 0x477, - CMSG_REQUEST_VEHICLE_NEXT_SEAT = 0x478, - CMSG_REQUEST_VEHICLE_SWITCH_SEAT = 0x479, - CMSG_PET_LEARN_TALENT = 0x47A, - CMSG_PET_UNLEARN_TALENTS = 0x47B, - SMSG_SET_PHASE_SHIFT = 0x47C, - SMSG_ALL_ACHIEVEMENT_DATA = 0x47D, - CMSG_FORCE_SAY_CHEAT = 0x47E, - SMSG_HEALTH_UPDATE = 0x47F, - SMSG_POWER_UPDATE = 0x480, - CMSG_GAMEOBJ_REPORT_USE = 0x481, - SMSG_HIGHEST_THREAT_UPDATE = 0x482, - SMSG_THREAT_UPDATE = 0x483, - SMSG_THREAT_REMOVE = 0x484, - SMSG_THREAT_CLEAR = 0x485, - SMSG_CONVERT_RUNE = 0x486, - SMSG_RESYNC_RUNES = 0x487, - SMSG_ADD_RUNE_POWER = 0x488, - CMSG_START_QUEST = 0x489, - CMSG_REMOVE_GLYPH = 0x48A, - CMSG_DUMP_OBJECTS = 0x48B, - SMSG_DUMP_OBJECTS_DATA = 0x48C, - CMSG_DISMISS_CRITTER = 0x48D, - SMSG_NOTIFY_DEST_LOC_SPELL_CAST = 0x48E, - CMSG_AUCTION_LIST_PENDING_SALES = 0x48F, - SMSG_AUCTION_LIST_PENDING_SALES = 0x490, - SMSG_MODIFY_COOLDOWN = 0x491, - SMSG_PET_UPDATE_COMBO_POINTS = 0x492, - CMSG_ENABLETAXI = 0x493, - SMSG_PRE_RESURRECT = 0x494, - SMSG_AURA_UPDATE_ALL = 0x495, - SMSG_AURA_UPDATE = 0x496, - CMSG_FLOOD_GRACE_CHEAT = 0x497, - SMSG_SERVER_FIRST_ACHIEVEMENT = 0x498, - SMSG_PET_LEARNED_SPELL = 0x499, - SMSG_PET_REMOVED_SPELL = 0x49A, - CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE = 0x49B, - CMSG_HEARTH_AND_RESURRECT = 0x49C, - SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA = 0x49D, - SMSG_CRITERIA_DELETED = 0x49E, - SMSG_ACHIEVEMENT_DELETED = 0x49F, - CMSG_SERVER_INFO_QUERY = 0x4A0, - SMSG_SERVER_INFO_RESPONSE = 0x4A1, - CMSG_CHECK_LOGIN_CRITERIA = 0x4A2, - SMSG_SERVER_BUCK_DATA_START = 0x4A3, - CMSG_SET_BREATH = 0x4A4, - CMSG_QUERY_VEHICLE_STATUS = 0x4A5, - SMSG_BATTLEGROUND_INFO_THROTTLED = 0x4A6, // empty, "You can't do that yet" - SMSG_PLAYER_VEHICLE_DATA = 0x4A7, // guid+uint32 (vehicle) - CMSG_PLAYER_VEHICLE_ENTER = 0x4A8, // uint64 - CMSG_CONTROLLER_EJECT_PASSENGER = 0x4A9, // uint64 - SMSG_PET_GUIDS = 0x4AA, - SMSG_CLIENTCACHE_VERSION = 0x4AB, - CMSG_CHANGE_GDF_ARENA_RATING = 0x4AC, - CMSG_SET_ARENA_TEAM_RATING_BY_INDEX = 0x4AD, - CMSG_SET_ARENA_TEAM_WEEKLY_GAMES = 0x4AE, - CMSG_SET_ARENA_TEAM_SEASON_GAMES = 0x4AF, - CMSG_SET_ARENA_MEMBER_WEEKLY_GAMES = 0x4B0, - CMSG_SET_ARENA_MEMBER_SEASON_GAMES = 0x4B1, - SMSG_ITEM_REFUND_INFO_RESPONSE = 0x4B2, - CMSG_ITEM_REFUND_INFO = 0x4B3, - CMSG_ITEM_REFUND = 0x4B4, // lua: ContainerRefundItemPurchase - SMSG_ITEM_REFUND_RESULT = 0x4B5, - CMSG_CORPSE_MAP_POSITION_QUERY = 0x4B6, // uint32 - SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE = 0x4B7, // 3*float+float - CMSG_UNUSED5 = 0x4B8, - CMSG_UNUSED6 = 0x4B9, - CMSG_CALENDAR_EVENT_SIGNUP = 0x4BA, // uint64 - SMSG_CALENDAR_CLEAR_PENDING_ACTION = 0x4BB, - SMSG_EQUIPMENT_SET_LIST = 0x4BC, // equipment manager list? - CMSG_EQUIPMENT_SET_SAVE = 0x4BD, - CMSG_UPDATE_PROJECTILE_POSITION = 0x4BE, - SMSG_SET_PROJECTILE_POSITION = 0x4BF, - SMSG_TALENTS_INFO = 0x4C0, - CMSG_LEARN_PREVIEW_TALENTS = 0x4C1, - CMSG_LEARN_PREVIEW_TALENTS_PET = 0x4C2, - CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE = 0x4C3, - CMSG_GM_GRANT_ACHIEVEMENT = 0x4C4, - CMSG_GM_REMOVE_ACHIEVEMENT = 0x4C5, - CMSG_GM_SET_CRITERIA_FOR_PLAYER = 0x4C6, - SMSG_ARENA_UNIT_DESTROYED = 0x4C7, - SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED = 0x4C8, // uint32 "Can't modify arena team while queued or in a match." - CMSG_PROFILEDATA_REQUEST = 0x4C9, - SMSG_PROFILEDATA_RESPONSE = 0x4CA, - CMSG_START_BATTLEFIELD_CHEAT = 0x4CB, - CMSG_END_BATTLEFIELD_CHEAT = 0x4CC, - SMSG_MULTIPLE_PACKETS = 0x4CD, - SMSG_MOVE_GRAVITY_DISABLE = 0x4CE, - CMSG_MOVE_GRAVITY_DISABLE_ACK = 0x4CF, - SMSG_MOVE_GRAVITY_ENABLE = 0x4D0, - CMSG_MOVE_GRAVITY_ENABLE_ACK = 0x4D1, - MSG_MOVE_GRAVITY_CHNG = 0x4D2, - SMSG_SPLINE_MOVE_GRAVITY_DISABLE = 0x4D3, - SMSG_SPLINE_MOVE_GRAVITY_ENABLE = 0x4D4, - CMSG_EQUIPMENT_SET_USE = 0x4D5, - SMSG_EQUIPMENT_SET_USE_RESULT = 0x4D6, - CMSG_FORCE_ANIM = 0x4D7, - SMSG_FORCE_ANIM = 0x4D8, - CMSG_CHAR_FACTION_CHANGE = 0x4D9, - SMSG_CHAR_FACTION_CHANGE = 0x4DA, - CMSG_PVP_QUEUE_STATS_REQUEST = 0x4DB, - SMSG_PVP_QUEUE_STATS = 0x4DC, - CMSG_SET_PAID_SERVICE_CHEAT = 0x4DD, - SMSG_BATTLEFIELD_MGR_ENTRY_INVITE = 0x4DE, // uint32 - CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE = 0x4DF, - SMSG_BATTLEFIELD_MGR_ENTERED = 0x4E0, // uint32, uint8, uint8 - SMSG_BATTLEFIELD_MGR_QUEUE_INVITE = 0x4E1, // uint32 - CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE = 0x4E2, - CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST = 0x4E3, - SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE = 0x4E4, // uint32, uint8 - SMSG_BATTLEFIELD_MGR_EJECT_PENDING = 0x4E5, // uint32 - SMSG_BATTLEFIELD_MGR_EJECTED = 0x4E6, // uint32, uint32, uint8 - CMSG_BATTLEFIELD_MGR_EXIT_REQUEST = 0x4E7, - SMSG_BATTLEFIELD_MGR_STATE_CHANGE = 0x4E8, // uint32, uint32 - CMSG_BATTLEFIELD_MANAGER_ADVANCE_STATE = 0x4E9, - CMSG_BATTLEFIELD_MANAGER_SET_NEXT_TRANSITION_TIME= 0x4EA, - MSG_SET_RAID_DIFFICULTY = 0x4EB, - CMSG_TOGGLE_XP_GAIN = 0x4EC, - SMSG_TOGGLE_XP_GAIN = 0x4ED, // enable/disable XP gain console message - SMSG_GMRESPONSE_DB_ERROR = 0x4EE, // empty - SMSG_GMRESPONSE_RECEIVED = 0x4EF, // uint32, uint32, string[2000], string[4000][4] - CMSG_GMRESPONSE_RESOLVE = 0x4F0, - SMSG_GMRESPONSE_STATUS_UPDATE = 0x4F1, // uint8 (1 - EVENT_GMSURVEY_DISPLAY, 0 - EVENT_UPDATE_TICKET) - SMSG_GMRESPONSE_CREATE_TICKET = 0x4F2, - CMSG_GMRESPONSE_CREATE_TICKET = 0x4F3, - CMSG_SERVERINFO = 0x4F4, - SMSG_SERVERINFO = 0x4F5, - CMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4F6, - SMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4F7, - CMSG_CHAR_RACE_CHANGE = 0x4F8, - MSG_VIEW_PHASE_SHIFT = 0x4F9, - SMSG_TALENTS_INVOLUNTARILY_RESET = 0x4FA, // uint8 - CMSG_DEBUG_SERVER_GEO = 0x4FB, - SMSG_DEBUG_SERVER_GEO = 0x4FC, - SMSG_LOOT_SLOT_CHANGED = 0x4FD, - UMSG_UPDATE_GROUP_INFO = 0x4FE, - CMSG_READY_FOR_ACCOUNT_DATA_TIMES = 0x4FF, - CMSG_QUERY_QUESTS_COMPLETED = 0x500, - SMSG_QUERY_QUESTS_COMPLETED_RESPONSE = 0x501, - CMSG_GM_REPORT_LAG = 0x502, - CMSG_AFK_MONITOR_INFO_REQUEST = 0x503, - SMSG_AFK_MONITOR_INFO_RESPONSE = 0x504, - CMSG_AFK_MONITOR_INFO_CLEAR = 0x505, - SMSG_CORPSE_NOT_IN_INSTANCE = 0x506, - CMSG_GM_NUKE_CHARACTER = 0x507, - CMSG_SET_ALLOW_LOW_LEVEL_RAID1 = 0x508, - CMSG_SET_ALLOW_LOW_LEVEL_RAID2 = 0x509, - SMSG_CAMERA_SHAKE = 0x50A, // uint32 SpellEffectCameraShakes.dbc index, uint32 - SMSG_SOCKET_GEMS_RESULT = 0x50B, - CMSG_SET_CHARACTER_MODEL = 0x50C, - SMSG_REDIRECT_CLIENT = 0x50D, // uint32 ip, uint16 port, uint32 unk, uint8[20] hash (ip + port, seed=sessionkey) - CMSG_REDIRECTION_FAILED = 0x50E, // something with networking - SMSG_SUSPEND_COMMS = 0x50F, - CMSG_SUSPEND_COMMS_ACK = 0x510, - SMSG_FORCE_SEND_QUEUED_PACKETS = 0x511, - CMSG_REDIRECTION_AUTH_PROOF = 0x512, - CMSG_DROP_NEW_CONNECTION = 0x513, - SMSG_SEND_ALL_COMBAT_LOG = 0x514, - SMSG_OPEN_LFG_DUNGEON_FINDER = 0x515, - SMSG_MOVE_SET_COLLISION_HGT = 0x516, - CMSG_MOVE_SET_COLLISION_HGT_ACK = 0x517, - MSG_MOVE_SET_COLLISION_HGT = 0x518, - CMSG_CLEAR_RANDOM_BG_WIN_TIME = 0x519, - CMSG_CLEAR_HOLIDAY_BG_WIN_TIME = 0x51A, - CMSG_COMMENTATOR_SKIRMISH_QUEUE_COMMAND = 0x51B, - SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1 = 0x51C, - SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2 = 0x51D, - SMSG_MULTIPLE_MOVES = 0x51E, // uncompressed version of SMSG_COMPRESSED_MOVES - NUM_MSG_TYPES = 0x51F + NUM_OPCODE_HANDLERS = (0x7FFF+1), + UNKNOWN_OPCODE = (0xFFFF+1), + NULL_OPCODE = 0, + COMPRESSED_OPCODE_MASK = 0x8000, + + CMSG_ACCEPT_LEVEL_GRANT = 0x0205, + CMSG_ACCEPT_TRADE = 0x7110, + CMSG_ACTIVATETAXI = 0x6E06, + CMSG_ACTIVATETAXIEXPRESS = 0x0515, + CMSG_ADDON_REGISTERED_PREFIXES = 0x0954, + CMSG_ADD_FRIEND = 0x6527, + CMSG_ADD_IGNORE = 0x4726, + CMSG_ADD_VOICE_IGNORE = 0x0F06, + CMSG_ALTER_APPEARANCE = 0x0914, + CMSG_AREATRIGGER = 0x0937, + CMSG_AREA_SPIRIT_HEALER_QUERY = 0x4907, + CMSG_AREA_SPIRIT_HEALER_QUEUE = 0x4815, + CMSG_ARENA_TEAM_ACCEPT = 0x2A25, + CMSG_ARENA_TEAM_CREATE = 0x04A1, + CMSG_ARENA_TEAM_DECLINE = 0x6925, + CMSG_ARENA_TEAM_DISBAND = 0x6504, + CMSG_ARENA_TEAM_INVITE = 0x2F27, + CMSG_ARENA_TEAM_LEADER = 0x4204, + CMSG_ARENA_TEAM_LEAVE = 0x0E16, + CMSG_ARENA_TEAM_QUERY = 0x0514, + CMSG_ARENA_TEAM_REMOVE = 0x2F05, + CMSG_ARENA_TEAM_ROSTER = 0x6F37, + CMSG_ATTACKSTOP = 0x4106, + CMSG_ATTACKSWING = 0x0926, + CMSG_AUCTION_LIST_BIDDER_ITEMS = 0x6937, + CMSG_AUCTION_LIST_ITEMS = 0x0324, + CMSG_AUCTION_LIST_OWNER_ITEMS = 0x0206, + CMSG_AUCTION_LIST_PENDING_SALES = 0x2C17, + CMSG_AUCTION_PLACE_BID = 0x2306, + CMSG_AUCTION_REMOVE_ITEM = 0x6426, + CMSG_AUCTION_SELL_ITEM = 0x4A06, + CMSG_AUTH_SESSION = 0x0449, + CMSG_AUTOBANK_ITEM = 0x2537, + CMSG_AUTOEQUIP_GROUND_ITEM = 0x0000, + CMSG_AUTOEQUIP_ITEM = 0x4304, + CMSG_AUTOEQUIP_ITEM_SLOT = 0x4A17, + CMSG_AUTOSTORE_BAG_ITEM = 0x0236, + CMSG_AUTOSTORE_BANK_ITEM = 0x0607, + CMSG_AUTOSTORE_GROUND_ITEM = 0x0000, + CMSG_AUTOSTORE_LOOT_ITEM = 0x0E34, + CMSG_AUTO_DECLINE_GUILD_INVITES = 0x2034, + CMSG_BANKER_ACTIVATE = 0x0005, + CMSG_BATTLEFIELD_JOIN = 0x0000, + CMSG_BATTLEFIELD_LEAVE = 0x3018, + CMSG_BATTLEFIELD_LIST = 0x3814, + CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE = 0x05A3, + CMSG_BATTLEFIELD_MGR_EXIT_REQUEST = 0x2490, + CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE = 0x0413, + CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST = 0x710C, + CMSG_BATTLEFIELD_PORT = 0x711A, + CMSG_BATTLEFIELD_REQUEST_SCORE_DATA = 0x0000, + CMSG_BATTLEFIELD_STATUS = 0x2500, + CMSG_BATTLEGROUND_PLAYER_POSITIONS = 0x3902, + CMSG_BATTLEMASTER_JOIN = 0x7902, + CMSG_BATTLEMASTER_JOIN_ARENA = 0x701C, + CMSG_BATTLEMASTER_JOIN_RATED = 0x3B18, + CMSG_BEGIN_TRADE = 0x721E, + CMSG_BINDER_ACTIVATE = 0x4006, + CMSG_BOT_DETECTED2 = 0x0000, + CMSG_BUG = 0x4035, + CMSG_BUSY_TRADE = 0x331C, + CMSG_BUYBACK_ITEM = 0x6C17, + CMSG_BUY_BANK_SLOT = 0x0425, + CMSG_BUY_ITEM = 0x0736, + CMSG_CALENDAR_ADD_EVENT = 0x0726, + CMSG_CALENDAR_ARENA_TEAM = 0x0204, + CMSG_CALENDAR_COMPLAIN = 0x4C36, + CMSG_CALENDAR_CONTEXT_EVENT_SIGNUP = 0x0000, + CMSG_CALENDAR_COPY_EVENT = 0x0207, + CMSG_CALENDAR_EVENT_INVITE = 0x2435, + CMSG_CALENDAR_EVENT_MODERATOR_STATUS = 0x6B35, + CMSG_CALENDAR_EVENT_REMOVE_INVITE = 0x4337, + CMSG_CALENDAR_EVENT_RSVP = 0x0227, + CMSG_CALENDAR_EVENT_SIGNUP = 0x6606, + CMSG_CALENDAR_EVENT_STATUS = 0x2D24, + CMSG_CALENDAR_GET_CALENDAR = 0x2814, + CMSG_CALENDAR_GET_EVENT = 0x6416, + CMSG_CALENDAR_GET_NUM_PENDING = 0x4D05, + CMSG_CALENDAR_GUILD_FILTER = 0x4A16, + CMSG_CALENDAR_REMOVE_EVENT = 0x6636, + CMSG_CALENDAR_UPDATE_EVENT = 0x2114, + CMSG_CANCEL_AURA = 0x0E26, + CMSG_CANCEL_AUTO_REPEAT_SPELL = 0x6C35, + CMSG_CANCEL_CAST = 0x0115, + CMSG_CANCEL_CHANNELLING = 0x6C25, + CMSG_CANCEL_GROWTH_AURA = 0x0000, + CMSG_CANCEL_MOUNT_AURA = 0x0635, + CMSG_CANCEL_QUEUED_SPELL = 0x7B1C, + CMSG_CANCEL_TEMP_ENCHANTMENT = 0x6C37, + CMSG_CANCEL_TRADE = 0x731E, + CMSG_CAST_SPELL = 0x4C07, + CMSG_CHANGEPLAYER_DIFFICULTY = 0x6107, + CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE = 0x7310, + CMSG_CHANNEL_ANNOUNCEMENTS = 0x1146, + CMSG_CHANNEL_BAN = 0x3D56, + CMSG_CHANNEL_DISPLAY_LIST = 0x2144, + CMSG_CHANNEL_INVITE = 0x0144, + CMSG_CHANNEL_KICK = 0x3156, + CMSG_CHANNEL_LIST = 0x1556, + CMSG_CHANNEL_MODERATE = 0x2944, + CMSG_CHANNEL_MODERATOR = 0x0146, + CMSG_CHANNEL_MUTE = 0x2554, + CMSG_CHANNEL_OWNER = 0x3D44, + CMSG_CHANNEL_PASSWORD = 0x2556, + CMSG_CHANNEL_ROSTER_INFO = 0x3546, + CMSG_CHANNEL_SET_OWNER = 0x3556, + CMSG_CHANNEL_SILENCE_ALL = 0x2154, + CMSG_CHANNEL_SILENCE_VOICE = 0x2D54, + CMSG_CHANNEL_UNBAN = 0x2D46, + CMSG_CHANNEL_UNMODERATOR = 0x1954, + CMSG_CHANNEL_UNMUTE = 0x3554, + CMSG_CHANNEL_UNSILENCE_ALL = 0x2546, + CMSG_CHANNEL_UNSILENCE_VOICE = 0x3146, + CMSG_CHANNEL_VOICE_OFF = 0x3144, + CMSG_CHANNEL_VOICE_ON = 0x1144, + CMSG_CHAR_CREATE = 0x4A36, + CMSG_CHAR_CUSTOMIZE = 0x2C34, + CMSG_CHAR_DELETE = 0x6425, + CMSG_CHAR_ENUM = 0x0502, + CMSG_CHAR_FACTION_CHANGE = 0x2735, + CMSG_CHAR_RACE_CHANGE = 0x0D24, + CMSG_CHAR_RENAME = 0x2327, + CMSG_CHAT_FILTERED = 0x0946, + CMSG_CHAT_IGNORED = 0x0D54, + CMSG_CLEAR_CHANNEL_WATCH = 0x2604, + CMSG_CLEAR_RAID_MARKER = 0x7300, + CMSG_CLEAR_TRADE_ITEM = 0x7018, + CMSG_COMMENTATOR_ENABLE = 0x0B07, + CMSG_COMMENTATOR_ENTER_INSTANCE = 0x4105, + CMSG_COMMENTATOR_EXIT_INSTANCE = 0x6136, + CMSG_COMMENTATOR_GET_MAP_INFO = 0x0026, + CMSG_COMMENTATOR_GET_PARTY_INFO = 0x2412, + CMSG_COMMENTATOR_GET_PLAYER_INFO = 0x0D14, + CMSG_COMMENTATOR_INSTANCE_COMMAND = 0x0917, + CMSG_COMMENTATOR_SKIRMISH_QUEUE_COMMAND = 0x0025, + CMSG_COMMENTATOR_START_WARGAME = 0x25A0, + CMSG_COMPLAIN = 0x0427, + CMSG_COMPLETE_CINEMATIC = 0x2116, + CMSG_COMPLETE_MOVIE = 0x4136, + CMSG_CONNECT_TO_FAILED = 0x2533, + CMSG_CONTACT_LIST = 0x4534, + CMSG_CORPSE_MAP_POSITION_QUERY = 0x6205, + CMSG_CREATURE_QUERY = 0x2706, + CMSG_DANCE_QUERY = 0x4E07, + CMSG_DECLINE_CHANNEL_INVITE = 0x0000, + CMSG_DEL_FRIEND = 0x6A15, + CMSG_DEL_IGNORE = 0x6D26, + CMSG_DEL_VOICE_IGNORE = 0x0024, + CMSG_DESTROY_ITEM = 0x4A27, + CMSG_DISMISS_CONTROLLED_VEHICLE = 0x3218, + CMSG_DISMISS_CRITTER = 0x4227, + CMSG_DUEL_ACCEPTED = 0x2136, + CMSG_DUEL_CANCELLED = 0x6624, + CMSG_EJECT_PASSENGER = 0x6927, + CMSG_EMOTE = 0x4C26, + CMSG_ENABLETAXI = 0x0C16, + CMSG_ENABLE_NAGLE = 0x4449, + CMSG_EQUIPMENT_SET_DELETE = 0x4D07, + CMSG_EQUIPMENT_SET_SAVE = 0x4F27, + CMSG_EQUIPMENT_SET_USE = 0x0417, + CMSG_FAR_SIGHT = 0x4835, + CMSG_FORCE_MOVE_ROOT_ACK = 0x701E, + CMSG_FORCE_MOVE_UNROOT_ACK = 0x7808, + CMSG_GAMEOBJECT_QUERY = 0x4017, + CMSG_GAMEOBJ_REPORT_USE = 0x4827, + CMSG_GAMEOBJ_USE = 0x4E17, + CMSG_GAMESPEED_SET = 0x0000, + CMSG_GAMETIME_SET = 0x0000, + CMSG_GETDEATHBINDZONE = 0x0000, + CMSG_GET_MAIL_LIST = 0x4D37, + CMSG_GET_MIRRORIMAGE_DATA = 0x0C25, + CMSG_GHOST = 0x0000, + CMSG_GMRESPONSE_RESOLVE = 0x6506, + CMSG_GMSURVEY_SUBMIT = 0x2724, + CMSG_GMTICKET_CREATE = 0x0137, + CMSG_GMTICKET_DELETETICKET = 0x6B14, + CMSG_GMTICKET_GETTICKET = 0x0326, + CMSG_GMTICKET_SYSTEMSTATUS = 0x4205, + CMSG_GMTICKET_UPDATETEXT = 0x0636, + CMSG_GM_INVIS = 0x0000, + CMSG_GM_NUKE = 0x0000, + CMSG_GM_REPORT_LAG = 0x6726, + CMSG_GM_SET_SECURITY_GROUP = 0x0000, + CMSG_GOSSIP_HELLO = 0x4525, + CMSG_GOSSIP_SELECT_OPTION = 0x0216, + CMSG_GRANT_LEVEL = 0x6D16, + CMSG_GROUP_ASSISTANT_LEADER = 0x6025, + CMSG_GROUP_CANCEL = 0x0000, + CMSG_GROUP_CHANGE_SUB_GROUP = 0x4124, + CMSG_GROUP_DISBAND = 0x2804, + CMSG_GROUP_INVITE = 0x0513, + CMSG_GROUP_INVITE_RESPONSE = 0x0410, + CMSG_GROUP_RAID_CONVERT = 0x6E27, + CMSG_GROUP_REQUEST_JOIN_UPDATES = 0x2583, + CMSG_GROUP_SET_LEADER = 0x4C17, + CMSG_GROUP_SET_ROLES = 0x25B1, + CMSG_GROUP_SWAP_SUB_GROUP = 0x0034, + CMSG_GROUP_UNINVITE = 0x0000, + CMSG_GROUP_UNINVITE_GUID = 0x2E07, + CMSG_GUILD_ACCEPT = 0x2531, + CMSG_GUILD_ACHIEVEMENT_MEMBERS = 0x3025, + CMSG_GUILD_ACHIEVEMENT_PROGRESS_QUERY = 0x3235, + CMSG_GUILD_ADD_RANK = 0x3030, + CMSG_GUILD_ASSIGN_MEMBER_RANK = 0x3032, + CMSG_GUILD_BANKER_ACTIVATE = 0x2E37, + CMSG_GUILD_BANK_BUY_TAB = 0x0C37, + CMSG_GUILD_BANK_DEPOSIT_MONEY = 0x0707, + CMSG_GUILD_BANK_LOG_QUERY = 0x3224, + CMSG_GUILD_BANK_MONEY_WITHDRAWN_QUERY = 0x1225, + CMSG_GUILD_BANK_NOTE = 0x0000, + CMSG_GUILD_BANK_QUERY_TAB = 0x2E35, + CMSG_GUILD_BANK_QUERY_TEXT = 0x3220, + CMSG_GUILD_BANK_SWAP_ITEMS = 0x2315, + CMSG_GUILD_BANK_UPDATE_TAB = 0x0106, + CMSG_GUILD_BANK_WITHDRAW_MONEY = 0x0037, + CMSG_GUILD_CHANGE_NAME_REQUEST = 0x1232, + CMSG_GUILD_DECLINE = 0x3231, + CMSG_GUILD_DEL_RANK = 0x3234, + CMSG_GUILD_DEMOTE = 0x1020, + CMSG_GUILD_DISBAND = 0x3226, + CMSG_GUILD_EVENT_LOG_QUERY = 0x1220, + CMSG_GUILD_INFO = 0x0000, + CMSG_GUILD_INFO_TEXT = 0x3227, + CMSG_GUILD_INVITE = 0x24B0, + CMSG_GUILD_LEAVE = 0x1021, + CMSG_GUILD_MEMBER_SEND_SOR_REQUEST = 0x3225, + CMSG_GUILD_MOTD = 0x1035, + CMSG_GUILD_NEWS_UPDATE_STICKY = 0x3223, + CMSG_GUILD_PERMISSIONS = 0x3022, + CMSG_GUILD_PROMOTE = 0x1030, + CMSG_GUILD_QUERY = 0x4426, + CMSG_GUILD_QUERY_NEWS = 0x3020, + CMSG_GUILD_QUERY_RANKS = 0x1026, + CMSG_GUILD_REMOVE = 0x1231, + CMSG_GUILD_REPLACE_GUILD_MASTER = 0x1034, + CMSG_GUILD_REQUEST_CHALLENGE_UPDATE = 0x1224, + CMSG_GUILD_REQUEST_MAX_DAILY_XP = 0x3232, + CMSG_GUILD_REQUEST_PARTY_STATE = 0x3900, + CMSG_GUILD_ROSTER = 0x1226, + CMSG_GUILD_SET_ACHIEVEMENT_TRACKING = 0x1027, + CMSG_GUILD_SET_GUILD_MASTER = 0x3034, + CMSG_GUILD_SET_NOTE = 0x1233, + CMSG_GUILD_SET_RANK_PERMISSIONS = 0x1024, + CMSG_GUILD_SWITCH_RANK = 0x1221, + CMSG_HEARTH_AND_RESURRECT = 0x4B34, + CMSG_IGNORE_TRADE = 0x7112, + CMSG_INITIATE_TRADE = 0x7916, + CMSG_INSPECT = 0x0927, + CMSG_INSPECT_HONOR_STATS = 0x791E, + CMSG_INSTANCE_LOCK_WARNING_RESPONSE = 0x6234, + CMSG_ITEM_REFUND = 0x6134, + CMSG_ITEM_REFUND_INFO = 0x2206, + CMSG_ITEM_TEXT_QUERY = 0x2406, + CMSG_JOIN_CHANNEL = 0x0156, + CMSG_KEEP_ALIVE = 0x0015, + CMSG_LEARN_PREVIEW_TALENTS = 0x2415, + CMSG_LEARN_PREVIEW_TALENTS_PET = 0x6E24, + CMSG_LEARN_TALENT = 0x0306, + CMSG_LEAVE_CHANNEL = 0x2D56, + CMSG_LFG_GET_STATUS = 0x2581, + CMSG_LFG_JOIN = 0x2430, + CMSG_LFG_LEAVE = 0x2433, + CMSG_LFG_LFR_JOIN = 0x0531, + CMSG_LFG_LFR_LEAVE = 0x0500, + CMSG_LFG_LOCK_INFO_REQUEST = 0x0412, + CMSG_LFG_PROPOSAL_RESULT = 0x0403, + CMSG_LFG_SET_BOOT_VOTE = 0x04B3, + CMSG_LFG_SET_COMMENT = 0x0530, + CMSG_LFG_SET_ROLES = 0x0480, + CMSG_LFG_TELEPORT = 0x2482, + CMSG_LF_GUILD_ADD_RECRUIT = 0x4448, + CMSG_LF_GUILD_BROWSE = 0x0548, + CMSG_LF_GUILD_DECLINE_RECRUIT = 0x1031, + CMSG_LF_GUILD_GET_APPLICATIONS = 0x1230, + CMSG_LF_GUILD_GET_RECRUITS = 0x3230, + CMSG_LF_GUILD_POST_REQUEST = 0x3237, + CMSG_LF_GUILD_REMOVE_RECRUIT = 0x3027, + CMSG_LF_GUILD_SET_GUILD_POST = 0x0448, + CMSG_LIST_INVENTORY = 0x2806, + CMSG_LOAD_SCREEN = 0x2422, + CMSG_LOGOUT_CANCEL = 0x2324, + CMSG_LOGOUT_REQUEST = 0x0A25, + CMSG_LOG_DISCONNECT = 0x446D, + CMSG_LOOT = 0x0127, + CMSG_LOOT_CURRENCY = 0x781C, + CMSG_LOOT_MASTER_GIVE = 0x4F35, + CMSG_LOOT_METHOD = 0x2F24, + CMSG_LOOT_MONEY = 0x6227, + CMSG_LOOT_RELEASE = 0x2007, + CMSG_LOOT_ROLL = 0x6934, + CMSG_MAIL_CREATE_TEXT_ITEM = 0x0B14, + CMSG_MAIL_DELETE = 0x6104, + CMSG_MAIL_MARK_AS_READ = 0x0C07, + CMSG_MAIL_RETURN_TO_SENDER = 0x0816, + CMSG_MAIL_TAKE_ITEM = 0x2B06, + CMSG_MAIL_TAKE_MONEY = 0x4034, + CMSG_MEETINGSTONE_INFO = 0x0000, + CMSG_MESSAGECHAT_ADDON_BATTLEGROUND = 0x0D46, + CMSG_MESSAGECHAT_ADDON_GUILD = 0x0544, + CMSG_MESSAGECHAT_ADDON_OFFICER = 0x3954, + CMSG_MESSAGECHAT_ADDON_PARTY = 0x0546, + CMSG_MESSAGECHAT_ADDON_RAID = 0x1D56, + CMSG_MESSAGECHAT_ADDON_WHISPER = 0x2146, + CMSG_MESSAGECHAT_AFK = 0x0D44, + CMSG_MESSAGECHAT_BATTLEGROUND = 0x2156, + CMSG_MESSAGECHAT_CHANNEL = 0x1D44, + CMSG_MESSAGECHAT_DND = 0x2946, + CMSG_MESSAGECHAT_EMOTE = 0x1156, + CMSG_MESSAGECHAT_GUILD = 0x3956, + CMSG_MESSAGECHAT_OFFICER = 0x1946, + CMSG_MESSAGECHAT_PARTY = 0x1D46, + CMSG_MESSAGECHAT_RAID = 0x2D44, + CMSG_MESSAGECHAT_RAID_WARNING = 0x0944, + CMSG_MESSAGECHAT_SAY = 0x1154, + CMSG_MESSAGECHAT_WHISPER = 0x0D56, + CMSG_MESSAGECHAT_YELL = 0x3544, + CMSG_MINIGAME_MOVE = 0x2A34, + CMSG_MOUNTSPECIAL_ANIM = 0x2807, + CMSG_MOVE_CHARM_TELEPORT_CHEAT = 0x0000, + CMSG_MOVE_CHNG_TRANSPORT = 0x3102, + CMSG_MOVE_ENABLE_SWIM_TO_FLY_TRANS_ACK = 0x0000, + CMSG_MOVE_FALL_RESET = 0x310A, + CMSG_MOVE_FEATHER_FALL_ACK = 0x3110, + CMSG_MOVE_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK = 0x310E, + CMSG_MOVE_FORCE_FLIGHT_SPEED_CHANGE_ACK = 0x7314, + CMSG_MOVE_FORCE_PITCH_RATE_CHANGE_ACK = 0x3100, + CMSG_MOVE_FORCE_RUN_BACK_SPEED_CHANGE_ACK = 0x3216, + CMSG_MOVE_FORCE_RUN_SPEED_CHANGE_ACK = 0x7818, + CMSG_MOVE_FORCE_SWIM_BACK_SPEED_CHANGE_ACK = 0x7A16, + CMSG_MOVE_FORCE_SWIM_SPEED_CHANGE_ACK = 0x7A10, + CMSG_MOVE_FORCE_TURN_RATE_CHANGE_ACK = 0x7316, + CMSG_MOVE_FORCE_WALK_SPEED_CHANGE_ACK = 0x7210, + CMSG_MOVE_GRAVITY_DISABLE_ACK = 0x3118, + CMSG_MOVE_GRAVITY_ENABLE_ACK = 0x700A, + CMSG_MOVE_HOVER_ACK = 0x3318, + CMSG_MOVE_KNOCK_BACK_ACK = 0x721C, + CMSG_MOVE_NOT_ACTIVE_MOVER = 0x7A1A, + CMSG_MOVE_SET_CAN_FLY = 0x720E, + CMSG_MOVE_SET_CAN_FLY_ACK = 0x790C, + CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK = 0x3014, + CMSG_MOVE_SET_COLLISION_HEIGHT_ACK = 0x7114, + CMSG_MOVE_SET_RELATIVE_POSITION = 0x0000, + CMSG_MOVE_SET_VEHICLE_REC_ID_ACK = 0x0000, + CMSG_MOVE_SPLINE_DONE = 0x790E, + CMSG_MOVE_TIME_SKIPPED = 0x7A0A, + CMSG_MOVE_TOGGLE_COLLISION_ACK = 0x0000, + CMSG_MOVE_WATER_WALK_ACK = 0x3B00, + CMSG_NAME_QUERY = 0x2224, + CMSG_NEW_SPELL_SLOT = 0x0000, + CMSG_NEXT_CINEMATIC_CAMERA = 0x2014, + CMSG_NPC_TEXT_QUERY = 0x4E24, + CMSG_OBJECT_UPDATE_FAILED = 0x3808, + CMSG_OBJECT_UPDATE_RESCUED = 0x3906, + CMSG_OFFER_PETITION = 0x4817, + CMSG_OPENING_CINEMATIC = 0x0A16, + CMSG_OPEN_ITEM = 0x6A34, + CMSG_OPT_OUT_OF_LOOT = 0x6B16, + CMSG_PAGE_TEXT_QUERY = 0x6614, + CMSG_PARTY_SILENCE = 0x6B26, + CMSG_PARTY_UNSILENCE = 0x4D24, + CMSG_PETITION_BUY = 0x4E05, + CMSG_PETITION_QUERY = 0x4424, + CMSG_PETITION_SHOWLIST = 0x4617, + CMSG_PETITION_SHOW_SIGNATURES = 0x4F15, + CMSG_PETITION_SIGN = 0x0E04, + CMSG_PET_ABANDON = 0x0C24, + CMSG_PET_ACTION = 0x0226, + CMSG_PET_CANCEL_AURA = 0x4B25, + CMSG_PET_CAST_SPELL = 0x6337, + CMSG_PET_LEARN_TALENT = 0x6725, + CMSG_PET_NAME_CACHE = 0x0000, + CMSG_PET_NAME_QUERY = 0x6F24, + CMSG_PET_RENAME = 0x6406, + CMSG_PET_SET_ACTION = 0x6904, + CMSG_PET_SPELL_AUTOCAST = 0x2514, + CMSG_PET_STOP_ATTACK = 0x6C14, + CMSG_PING = 0x444D, + CMSG_PLAYED_TIME = 0x0804, + CMSG_PLAYER_DIFFICULTY_CHANGE = 0x0000, + CMSG_PLAYER_LOGIN = 0x05B1, + CMSG_PLAYER_LOGOUT = 0x0000, + CMSG_PLAYER_VEHICLE_ENTER = 0x2705, + CMSG_PLAY_DANCE = 0x6914, + CMSG_PUSHQUESTTOPARTY = 0x4B14, + CMSG_PVP_LOG_DATA = 0x7308, + CMSG_QUERY_BATTLEFIELD_STATE = 0x7202, + CMSG_QUERY_GUILD_MEMBERS_FOR_RECIPE = 0x1036, + CMSG_QUERY_GUILD_MEMBER_RECIPES = 0x1037, + CMSG_QUERY_GUILD_RECIPES = 0x3033, + CMSG_QUERY_GUILD_REWARDS = 0x3012, + CMSG_QUERY_GUILD_XP = 0x1237, + CMSG_QUERY_INSPECT_ACHIEVEMENTS = 0x4D27, + CMSG_QUERY_QUESTS_COMPLETED = 0x2317, + CMSG_QUERY_TIME = 0x0A36, + CMSG_QUESTGIVER_ACCEPT_QUEST = 0x6B37, + CMSG_QUESTGIVER_CANCEL = 0x0000, + CMSG_QUESTGIVER_CHOOSE_REWARD = 0x2125, + CMSG_QUESTGIVER_COMPLETE_QUEST = 0x0114, + CMSG_QUESTGIVER_HELLO = 0x0D17, + CMSG_QUESTGIVER_QUERY_QUEST = 0x2F14, + CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 0x0000, + CMSG_QUESTGIVER_REQUEST_REWARD = 0x2534, + CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x6305, + CMSG_QUESTGIVER_STATUS_QUERY = 0x4407, + CMSG_QUESTLOG_REMOVE_QUEST = 0x0D16, + CMSG_QUESTLOG_SWAP_QUEST = 0x0000, + CMSG_QUEST_CONFIRM_ACCEPT = 0x0D15, + CMSG_QUEST_NPC_QUERY = 0x7302, + CMSG_QUEST_POI_QUERY = 0x4037, + CMSG_QUEST_QUERY = 0x0D06, + CMSG_RANDOMIZE_CHAR_NAME = 0x2413, + CMSG_READY_FOR_ACCOUNT_DATA_TIMES = 0x2B16, + CMSG_READ_ITEM = 0x2F16, + CMSG_REALM_SPLIT = 0x2906, + CMSG_RECLAIM_CORPSE = 0x4036, + CMSG_REDIRECTION_AUTH_PROOF = 0x044D, + CMSG_REFORGE_ITEM = 0x331A, + CMSG_REORDER_CHARACTERS = 0x0593, + CMSG_REPAIR_ITEM = 0x2917, + CMSG_REPLACE_ACCOUNT_DATA = 0x0000, + CMSG_REPOP_REQUEST = 0x6235, + CMSG_REPORT_PVP_AFK = 0x6734, + CMSG_REQUEST_ACCOUNT_DATA = 0x6505, + CMSG_REQUEST_CATEGORY_COOLDOWNS = 0x7102, + CMSG_REQUEST_CEMETERY_LIST = 0x720A, + CMSG_REQUEST_HOTFIX = 0x2401, + CMSG_REQUEST_INSPECT_RATED_BG_STATS = 0x3010, + CMSG_REQUEST_PARTY_MEMBER_STATS = 0x0C04, + CMSG_REQUEST_PET_INFO = 0x4924, + CMSG_REQUEST_PVP_OPTIONS_ENABLED = 0x24A1, + CMSG_REQUEST_PVP_REWARDS = 0x780C, + CMSG_REQUEST_RAID_INFO = 0x2F26, + CMSG_REQUEST_RATED_BG_INFO = 0x2423, + CMSG_REQUEST_RATED_BG_STATS = 0x05B3, + CMSG_REQUEST_RESEARCH_HISTORY = 0x3306, + CMSG_REQUEST_VEHICLE_EXIT = 0x2B35, + CMSG_REQUEST_VEHICLE_NEXT_SEAT = 0x4434, + CMSG_REQUEST_VEHICLE_PREV_SEAT = 0x4C04, + CMSG_REQUEST_VEHICLE_SWITCH_SEAT = 0x4C14, + CMSG_RESET_FACTION_CHEAT = 0x4469, + CMSG_RESET_INSTANCES = 0x6E14, + CMSG_RESURRECT_RESPONSE = 0x6827, + CMSG_RETURN_TO_GRAVEYARD = 0x301E, + CMSG_ROLE_POLL_BEGIN = 0x0430, + CMSG_SAVE_CUF_PROFILES = 0x730E, + CMSG_SAVE_PLAYER = 0x0000, + CMSG_SEARCH_LFG_JOIN = 0x0000, + CMSG_SEARCH_LFG_LEAVE = 0x0000, + CMSG_SELF_RES = 0x6115, + CMSG_SELL_ITEM = 0x4E15, + CMSG_SEND_MAIL = 0x0523, + CMSG_SEND_SOR_REQUEST_VIA_ADDRESS = 0x0420, + CMSG_SEND_SOR_REQUEST_VIA_BNET_ACCOUNT_ID = 0x0482, + CMSG_SERVERTIME = 0x0000, + CMSG_SETDEATHBINDPOINT = 0x0000, + CMSG_SETSHEATHED = 0x4326, + CMSG_SET_ACTIONBAR_TOGGLES = 0x2506, + CMSG_SET_ACTION_BUTTON = 0x6F06, + CMSG_SET_ACTIVE_MOVER = 0x3314, + CMSG_SET_ACTIVE_VOICE_CHANNEL = 0x4305, + CMSG_SET_ALLOW_LOW_LEVEL_RAID1 = 0x4435, + CMSG_SET_ALLOW_LOW_LEVEL_RAID2 = 0x0536, + CMSG_SET_CHANNEL_WATCH = 0x4517, + CMSG_SET_CONTACT_NOTES = 0x6135, + CMSG_SET_CURRENCY_FLAGS = 0x7306, + CMSG_SET_EVERYONE_IS_ASSISTANT = 0x2530, + CMSG_SET_FACTION_ATWAR = 0x0706, + CMSG_SET_FACTION_CHEAT = 0x0000, + CMSG_SET_FACTION_INACTIVE = 0x0E37, + CMSG_SET_GUILD_BANK_TEXT = 0x3023, + CMSG_SET_LFG_COMMENT = 0x0000, + CMSG_SET_PET_SLOT = 0x3A04, + CMSG_SET_PLAYER_DECLINED_NAMES = 0x6316, + CMSG_SET_PREFERED_CEMETERY = 0x311E, + CMSG_SET_PRIMARY_TALENT_TREE = 0x4524, + CMSG_SET_RELATIVE_POSITION = 0x311A, + CMSG_SET_SAVED_INSTANCE_EXTEND = 0x6706, + CMSG_SET_SELECTION = 0x0506, + CMSG_SET_SKILL_CHEAT = 0x0000, + CMSG_SET_TAXI_BENCHMARK_MODE = 0x4314, + CMSG_SET_TITLE = 0x2117, + CMSG_SET_TRADE_CURRENCY = 0x3312, + CMSG_SET_TRADE_GOLD = 0x3008, + CMSG_SET_TRADE_ITEM = 0x7B0C, + CMSG_SET_VEHICLE_REC_ID_ACK = 0x3108, + CMSG_SET_WATCHED_FACTION = 0x2434, + CMSG_SHOWING_CLOAK = 0x4135, + CMSG_SHOWING_HELM = 0x0735, + CMSG_SOCKET_GEMS = 0x2F04, + CMSG_SPELLCLICK = 0x0805, + CMSG_SPIRIT_HEALER_ACTIVATE = 0x2E26, + CMSG_SPLIT_ITEM = 0x0F17, + CMSG_STANDSTATECHANGE = 0x0535, + CMSG_START_QUEST = 0x0000, + CMSG_STOP_DANCE = 0x2907, + CMSG_STORE_LOOT_IN_SLOT = 0x0000, + CMSG_SUBMIT_BUG = 0x2520, + CMSG_SUBMIT_COMPLAIN = 0x2501, + CMSG_SUGGESTION_SUBMIT = 0x2512, + CMSG_SUMMON_RESPONSE = 0x6F27, + CMSG_SUSPEND_TOKEN = 0x046D, + CMSG_SWAP_INV_ITEM = 0x2614, + CMSG_SWAP_ITEM = 0x6326, + CMSG_SYNC_DANCE = 0x0036, + CMSG_TAXICLEARALLNODES = 0x0000, + CMSG_TAXIENABLEALLNODES = 0x0000, + CMSG_TAXINODE_STATUS_QUERY = 0x2F25, + CMSG_TAXIQUERYAVAILABLENODES = 0x6C06, + CMSG_TAXISHOWNODES = 0x0000, + CMSG_TELEPORT_TO_UNIT = 0x4206, + CMSG_TEXT_EMOTE = 0x2E24, + CMSG_TIME_ADJUSTMENT_RESPONSE = 0x3818, + CMSG_TIME_SYNC_RESP = 0x3B0C, + CMSG_TIME_SYNC_RESP_FAILED = 0x710A, + CMSG_TOGGLE_PVP = 0x6815, + CMSG_TOTEM_DESTROYED = 0x4207, + CMSG_TRAINER_BUY_SPELL = 0x4415, + CMSG_TRAINER_LIST = 0x2336, + CMSG_TRANSMOGRIFY_ITEMS = 0x3B0E, + CMSG_TRIGGER_CINEMATIC_CHEAT = 0x0000, + CMSG_TURN_IN_PETITION = 0x0B27, + CMSG_TUTORIAL_CLEAR = 0x6515, + CMSG_TUTORIAL_FLAG = 0x6C26, + CMSG_TUTORIAL_RESET = 0x2726, + CMSG_UNACCEPT_TRADE = 0x391A, + CMSG_UNLEARN_SKILL = 0x6106, + CMSG_UNLEARN_SPECIALIZATION = 0x3210, + CMSG_UNREGISTER_ALL_ADDON_PREFIXES = 0x3D54, + CMSG_UPDATE_ACCOUNT_DATA = 0x4736, + CMSG_UPDATE_MISSILE_TRAJECTORY = 0x781E, + CMSG_UPDATE_PROJECTILE_POSITION = 0x0E24, + CMSG_USED_FOLLOW = 0x7912, + CMSG_USE_ITEM = 0x2C06, + CMSG_VIOLENCE_LEVEL = 0x7816, + CMSG_VOICE_SESSION_ENABLE = 0x2314, + CMSG_VOID_STORAGE_QUERY = 0x790A, + CMSG_VOID_STORAGE_TRANSFER = 0x380E, + CMSG_VOID_STORAGE_UNLOCK = 0x7B14, + CMSG_VOID_SWAP_ITEM = 0x3204, + CMSG_WARDEN_DATA = 0x25A2, + CMSG_WARGAME_ACCEPT = 0x2410, + CMSG_WARGAME_START = 0x05A0, + CMSG_WHO = 0x6C15, + CMSG_WHOIS = 0x6B05, + CMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4605, + CMSG_WORLD_TELEPORT = 0x24B2, + CMSG_WRAP_ITEM = 0x4F06, + CMSG_ZONEUPDATE = 0x4F37, + MSG_AUCTION_HELLO = 0x2307, + MSG_CHANNEL_START = 0x0A15, // SMSG only? + MSG_CHANNEL_UPDATE = 0x2417, // SMSG only? + MSG_CORPSE_QUERY = 0x4336, + MSG_GM_BIND_OTHER = 0x0000, + MSG_GM_SHOWLABEL = 0x0000, + MSG_GM_SUMMON = 0x0000, + MSG_INSPECT_ARENA_TEAMS = 0x2704, + MSG_LIST_STABLED_PETS = 0x0834, + MSG_MINIMAP_PING = 0x6635, + MSG_MOVE_CHARM_TELEPORT_CHEAT = 0x7A08, + MSG_MOVE_FALL_LAND = 0x380A, + MSG_MOVE_HEARTBEAT = 0x3914, + MSG_MOVE_JUMP = 0x7A06, + MSG_MOVE_SET_ALL_SPEED_CHEAT = 0x0000, + MSG_MOVE_SET_COLLISION_HEIGHT = 0x0000, + MSG_MOVE_SET_FACING = 0x7914, + MSG_MOVE_SET_FLIGHT_SPEED_CHEAT = 0x0000, + MSG_MOVE_SET_PITCH = 0x7312, + MSG_MOVE_SET_RAW_POSITION_ACK = 0x0000, + MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT = 0x0000, + MSG_MOVE_SET_RUN_MODE = 0x791A, + MSG_MOVE_SET_RUN_SPEED_CHEAT = 0x0000, + MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT = 0x0000, + MSG_MOVE_SET_SWIM_SPEED_CHEAT = 0x0000, + MSG_MOVE_SET_TURN_RATE_CHEAT = 0x0000, + MSG_MOVE_SET_WALK_MODE = 0x7002, + MSG_MOVE_SET_WALK_SPEED_CHEAT = 0x0000, + MSG_MOVE_START_ASCEND = 0x390A, + MSG_MOVE_START_BACKWARD = 0x330A, + MSG_MOVE_START_DESCEND = 0x3800, + MSG_MOVE_START_FORWARD = 0x7814, + MSG_MOVE_START_PITCH_DOWN = 0x3908, + MSG_MOVE_START_PITCH_UP = 0x3304, + MSG_MOVE_START_STRAFE_LEFT = 0x3A16, + MSG_MOVE_START_STRAFE_RIGHT = 0x3A02, + MSG_MOVE_START_SWIM = 0x3206, + MSG_MOVE_START_TURN_LEFT = 0x700C, + MSG_MOVE_START_TURN_RIGHT = 0x7000, + MSG_MOVE_STOP = 0x320A, + MSG_MOVE_STOP_ASCEND = 0x7B00, + MSG_MOVE_STOP_PITCH = 0x7216, + MSG_MOVE_STOP_STRAFE = 0x3002, + MSG_MOVE_STOP_SWIM = 0x3802, + MSG_MOVE_STOP_TURN = 0x331E, + MSG_MOVE_TELEPORT = 0x55A0, + MSG_MOVE_TELEPORT_ACK = 0x390C, + MSG_MOVE_TELEPORT_CHEAT = 0x3A10, + MSG_MOVE_TIME_SKIPPED = 0x19B3, + MSG_MOVE_TOGGLE_COLLISION_CHEAT = 0x7B04, + MSG_MOVE_TOGGLE_FALL_LOGGING = 0x0000, + MSG_MOVE_TOGGLE_LOGGING = 0x0000, + MSG_MOVE_UPDATE_MOUSE = 0x0000, + MSG_MOVE_WORLDPORT_ACK = 0x2411, + MSG_NOTIFY_PARTY_SQUELCH = 0x4D06, + MSG_PARTY_ASSIGNMENT = 0x0424, + MSG_PETITION_DECLINE = 0x4905, + MSG_PETITION_RENAME = 0x4005, + MSG_PVP_LOG_DATA = 0x0000, + MSG_QUERY_NEXT_MAIL_TIME = 0x0F04, + MSG_QUEST_PUSH_RESULT = 0x4515, + MSG_RAID_READY_CHECK = 0x2304, + MSG_RAID_READY_CHECK_CONFIRM = 0x4F05, + MSG_RAID_READY_CHECK_FINISHED = 0x2E15, + MSG_RAID_TARGET_UPDATE = 0x2C36, + MSG_RANDOM_ROLL = 0x0905, + MSG_SAVE_GUILD_EMBLEM = 0x2404, + MSG_SET_DUNGEON_DIFFICULTY = 0x4925, + MSG_SET_RAID_DIFFICULTY = 0x0614, + MSG_START_MOVE_FORWARD = 0x0000, + MSG_TABARDVENDOR_ACTIVATE = 0x6926, + MSG_TALENT_WIPE_CONFIRM = 0x0107, + MSG_VERIFY_CONNECTIVITY = 0x4F57, + SMSG_ACCOUNT_DATA_TIMES = 0x4B05, + SMSG_ACCOUNT_INFO_RESPONSE = 0x10A7, + SMSG_ACCOUNT_RESTRICTED_WARNING = 0x51A7, + SMSG_ACHIEVEMENT_DELETED = 0x6A16, + SMSG_ACHIEVEMENT_EARNED = 0x4405, + SMSG_ACTION_BUTTONS = 0x38B5, + SMSG_ACTIVATETAXIREPLY = 0x6A37, + SMSG_ADDON_INFO = 0x2C14, + SMSG_ADD_RUNE_POWER = 0x6915, + SMSG_AI_REACTION = 0x0637, + SMSG_ALL_ACHIEVEMENT_DATA = 0x58B1, + SMSG_AREA_SPIRIT_HEALER_TIME = 0x0734, + SMSG_AREA_TRIGGER_MESSAGE = 0x4505, + SMSG_AREA_TRIGGER_MOVEMENT_UPDATE = 0x3DB1, + SMSG_ARENA_ERROR = 0x2D17, + SMSG_ARENA_UNIT_DESTROYED = 0x2637, + SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED = 0x6E34, + SMSG_ARENA_TEAM_COMMAND_RESULT = 0x39B3, + SMSG_ARENA_TEAM_EVENT = 0x0617, + SMSG_ARENA_TEAM_INVITE = 0x0F36, + SMSG_ARENA_TEAM_QUERY_RESPONSE = 0x6336, + SMSG_ARENA_TEAM_ROSTER = 0x2717, + SMSG_ARENA_TEAM_STATS = 0x4425, + SMSG_ATTACKERSTATEUPDATE = 0x0B25, + SMSG_ATTACKSTART = 0x2D15, + SMSG_ATTACKSTOP = 0x0934, + SMSG_ATTACKSWING_BADFACING = 0x0B36, + SMSG_ATTACKSWING_CANT_ATTACK = 0x0016, + SMSG_ATTACKSWING_DEADTARGET = 0x2B26, + SMSG_ATTACKSWING_NOTINRANGE = 0x6C07, + SMSG_AUCTION_BIDDER_LIST_RESULT = 0x0027, + SMSG_AUCTION_BIDDER_NOTIFICATION = 0x4E27, + SMSG_AUCTION_COMMAND_RESULT = 0x4C25, + SMSG_AUCTION_LIST_PENDING_SALES = 0x6A27, + SMSG_AUCTION_LIST_RESULT = 0x6637, + SMSG_AUCTION_OWNER_LIST_RESULT = 0x6C34, + SMSG_AUCTION_OWNER_NOTIFICATION = 0x4116, + SMSG_AUCTION_REMOVED_NOTIFICATION = 0x2334, + SMSG_AURACASTLOG = 0x0000, + SMSG_AURA_POINTS_DEPLETED = 0x7CB7, + SMSG_AURA_UPDATE = 0x4707, + SMSG_AURA_UPDATE_ALL = 0x6916, + SMSG_AUTH_CHALLENGE = 0x4542, + SMSG_AUTH_RESPONSE = 0x5DB6, + SMSG_AVAILABLE_VOICE_CHANNEL = 0x2E16, + SMSG_AVERAGE_ITEM_LEVEL_INFORM = 0x5DA7, + SMSG_BARBER_SHOP_RESULT = 0x6125, + SMSG_BATTLEFIELD_LIST = 0x71B5, + SMSG_BATTLEFIELD_MGR_EJECTED = 0x7DB7, + SMSG_BATTLEFIELD_MGR_EJECT_PENDING = 0x34A2, + SMSG_BATTLEFIELD_MGR_ENTERED = 0x5CA0, + SMSG_BATTLEFIELD_MGR_ENTRY_INVITE = 0x34B3, + SMSG_BATTLEFIELD_MGR_EXIT_REQUEST = 0x51B1, + SMSG_BATTLEFIELD_MGR_QUEUE_INVITE = 0x15A6, + SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE = 0x79B6, + SMSG_BATTLEFIELD_MGR_STATE_CHANGE = 0x35B4, + SMSG_BATTLEFIELD_PLAYER_POSITIONS = 0x58B4, + SMSG_BATTLEFIELD_PORT_DENIED = 0x35A3, + SMSG_BATTLEFIELD_RATED_INFO = 0x54A3, + SMSG_BATTLEFIELD_STATUS = 0x7DA1, + SMSG_BATTLEFIELD_STATUS_QUEUED = 0x35A1, + SMSG_BATTLEFIELD_STATUS_ACTIVE = 0x74A4, + SMSG_BATTLEFIELD_STATUS_NEEDCONFIRMATION = 0x59A0, + SMSG_BATTLEFIELD_STATUS_WAITFORGROUPS = 0x75A2, + SMSG_BATTLEFIELD_STATUS_FAILED = 0x71A7, + SMSG_BATTLEGROUND_INFO_THROTTLED = 0x34B2, + SMSG_BATTLEGROUND_PLAYER_JOINED = 0x50B0, + SMSG_BATTLEGROUND_PLAYER_LEFT = 0x59A6, + SMSG_BINDER_CONFIRM = 0x2835, + SMSG_BINDPOINTUPDATE = 0x0527, + SMSG_BINDZONEREPLY = 0x0000, + SMSG_BREAK_TARGET = 0x0105, + SMSG_BUY_BANK_SLOT_RESULT = 0x4806, + SMSG_BUY_FAILED = 0x6435, + SMSG_BUY_ITEM = 0x0F26, + SMSG_CALENDAR_ACTION_PENDING = 0x0000, + SMSG_CALENDAR_ARENA_TEAM = 0x0615, + SMSG_CALENDAR_CLEAR_PENDING_ACTION = 0x2106, + SMSG_CALENDAR_COMMAND_RESULT = 0x6F36, + SMSG_CALENDAR_EVENT_INVITE = 0x4E16, + SMSG_CALENDAR_EVENT_INVITE_ALERT = 0x2A05, + SMSG_CALENDAR_EVENT_INVITE_NOTES = 0x0E17, + SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT = 0x2535, + SMSG_CALENDAR_EVENT_INVITE_REMOVED = 0x0725, + SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT = 0x2617, + SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT = 0x6625, + SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT = 0x6B06, + SMSG_CALENDAR_EVENT_REMOVED_ALERT = 0x6D35, + SMSG_CALENDAR_EVENT_STATUS = 0x2A27, + SMSG_CALENDAR_EVENT_UPDATED_ALERT = 0x0907, + SMSG_CALENDAR_FILTER_GUILD = 0x4A26, + SMSG_CALENDAR_RAID_LOCKOUT_ADDED = 0x2305, + SMSG_CALENDAR_RAID_LOCKOUT_REMOVED = 0x2E25, + SMSG_CALENDAR_RAID_LOCKOUT_UPDATED = 0x4636, + SMSG_CALENDAR_SEND_CALENDAR = 0x6805, + SMSG_CALENDAR_SEND_EVENT = 0x0C35, + SMSG_CALENDAR_SEND_NUM_PENDING = 0x0C17, + SMSG_CALENDAR_UPDATE_INVITE_LIST = 0x0000, + SMSG_CAMERA_SHAKE = 0x4214, + SMSG_CANCEL_AUTO_REPEAT = 0x6436, + SMSG_CANCEL_COMBAT = 0x4F04, + SMSG_CAST_FAILED = 0x4D16, + SMSG_CHANNEL_LIST = 0x2214, + SMSG_CHANNEL_MEMBER_COUNT = 0x6414, + SMSG_CHANNEL_NOTIFY = 0x0825, + SMSG_CHARACTER_LOGIN_FAILED = 0x4417, + SMSG_CHAR_CREATE = 0x2D05, + SMSG_CHAR_CUSTOMIZE = 0x4F16, + SMSG_CHAR_DELETE = 0x0304, + SMSG_CHAR_ENUM = 0x10B0, + SMSG_CHAR_FACTION_CHANGE = 0x4C06, + SMSG_CHAR_RENAME = 0x2024, + SMSG_CHAT_IGNORED_ACCOUNT_MUTED = 0x15A4, + SMSG_CHAT_NOT_IN_PARTY = 0x6A14, + SMSG_CHAT_PLAYER_AMBIGUOUS = 0x2F34, + SMSG_CHAT_PLAYER_NOT_FOUND = 0x2526, + SMSG_CHAT_RESTRICTED = 0x6536, + SMSG_CHAT_SERVER_DISCONNECTED = 0x6D34, + SMSG_CHAT_SERVER_RECONNECTED = 0x6905, + SMSG_CHAT_WRONG_FACTION = 0x6724, + SMSG_CHECK_FOR_BOTS = 0x0000, + SMSG_CLEAR_BOSS_EMOTES = 0x19A3, + SMSG_CLEAR_COOLDOWN = 0x0627, + SMSG_CLEAR_COOLDOWNS = 0x59B4, + SMSG_CLEAR_FAR_SIGHT_IMMEDIATE = 0x2A04, + SMSG_CLEAR_TARGET = 0x4B26, + SMSG_CLIENTCACHE_VERSION = 0x2734, + SMSG_CLIENT_CONTROL_UPDATE = 0x2837, + SMSG_COMBAT_EVENT_FAILED = 0x2B07, + SMSG_COMBAT_LOG_MULTIPLE = 0x0000, + SMSG_COMMENTATOR_MAP_INFO = 0x0327, + SMSG_COMMENTATOR_PARTY_INFO = 0x38B0, + SMSG_COMMENTATOR_PLAYER_INFO = 0x2F36, + SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1 = 0x2126, + SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2 = 0x6814, + SMSG_COMMENTATOR_STATE_CHANGED = 0x0737, + SMSG_COMPLAIN_RESULT = 0x6D24, + SMSG_COMPRESSED_MOVES = 0x0517, + SMSG_COMSAT_CONNECT_FAIL = 0x6317, + SMSG_COMSAT_DISCONNECT = 0x0316, + SMSG_COMSAT_RECONNECT_TRY = 0x4D35, + SMSG_CONTACT_LIST = 0x6017, + SMSG_CONVERT_RUNE = 0x4F14, + SMSG_COOLDOWN_CHEAT = 0x4537, + SMSG_COOLDOWN_EVENT = 0x4F26, + SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE = 0x0E35, + SMSG_CORPSE_NOT_IN_INSTANCE = 0x2A14, + SMSG_CORPSE_RECLAIM_DELAY = 0x0D34, + SMSG_CREATURE_QUERY_RESPONSE = 0x6024, + SMSG_CRITERIA_DELETED = 0x2915, + SMSG_CRITERIA_UPDATE = 0x6E37, + SMSG_CROSSED_INEBRIATION_THRESHOLD = 0x2036, + SMSG_CURRENCY_LOOT_REMOVED = 0x1DB4, + SMSG_CURRENCY_LOOT_RESTORED = 0x30A0, + SMSG_CUSTOM_LOAD_SCREEN = 0x1DB6, + SMSG_DAMAGE_CALC_LOG = 0x2436, + SMSG_DAMAGE_DONE_OBSOLETE = 0x0000, + SMSG_DANCE_QUERY_RESPONSE = 0x2F06, + SMSG_DB_REPLY = 0x38A4, + SMSG_DEATH_RELEASE_LOC = 0x2F07, + SMSG_DEBUG_RUNE_REGEN = 0x31B3, + SMSG_DEFENSE_MESSAGE = 0x0314, + SMSG_DESTROY_OBJECT = 0x4724, + SMSG_DESTRUCTIBLE_BUILDING_DAMAGE = 0x4825, + SMSG_DIFFERENT_INSTANCE_FROM_PARTY = 0x15B1, + SMSG_DISENCHANT_CREDIT = 0x55A2, + SMSG_DISMOUNT = 0x2135, + SMSG_DISMOUNTRESULT = 0x0D25, + SMSG_DISPEL_FAILED = 0x0307, + SMSG_DISPLAY_GAME_ERROR = 0x31A6, + SMSG_DONT_AUTO_PUSH_SPELLS_TO_ACTION_BAR = 0x38A2, + SMSG_DROP_NEW_CONNECTION = 0x4D40, + SMSG_DUEL_COMPLETE = 0x2527, + SMSG_DUEL_COUNTDOWN = 0x4836, + SMSG_DUEL_INBOUNDS = 0x0A27, + SMSG_DUEL_OUTOFBOUNDS = 0x0C26, + SMSG_DUEL_REQUESTED = 0x4504, + SMSG_DUEL_WINNER = 0x2D36, + SMSG_DUMP_RIDE_TICKETS_RESPONSE = 0x11A3, + SMSG_DURABILITY_DAMAGE_DEATH = 0x4C27, + SMSG_ECHO_PARTY_SQUELCH = 0x0814, + SMSG_EMOTE = 0x0A34, + SMSG_ENABLE_BARBER_SHOP = 0x2D16, + SMSG_ENCHANTMENTLOG = 0x6035, + SMSG_ENVIRONMENTALDAMAGELOG = 0x6C05, + SMSG_EQUIPMENT_SET_LIST = 0x2E04, + SMSG_EQUIPMENT_SET_SAVED = 0x2216, + SMSG_EQUIPMENT_SET_USE_RESULT = 0x2424, + SMSG_EXPECTED_SPAM_RECORDS = 0x4D36, + SMSG_EXPLORATION_EXPERIENCE = 0x6716, + SMSG_FAILED_PLAYER_CONDITION = 0x19A4, + SMSG_FEATURE_SYSTEM_STATUS = 0x3DB7, + SMSG_FEIGN_DEATH_RESISTED = 0x0D05, + SMSG_FISH_ESCAPED = 0x2205, + SMSG_FISH_NOT_HOOKED = 0x0A17, + SMSG_FLIGHT_SPLINE_SYNC = 0x0924, + SMSG_FLOOD_DETECTED = 0x0542, + SMSG_FORCEACTIONSHOW = 0x0000, + SMSG_FORCED_DEATH_UPDATE = 0x2606, + SMSG_FORCE_DISPLAY_UPDATE = 0x0000, + SMSG_FORCE_SEND_QUEUED_PACKETS = 0x0140, + SMSG_FORCE_SET_VEHICLE_REC_ID = 0x70A1, + SMSG_FORGE_MASTER_SET = 0x70B7, + SMSG_FRIEND_STATUS = 0x0717, + SMSG_GAMEOBJECT_CUSTOM_ANIM = 0x4936, + SMSG_GAMEOBJECT_DESPAWN_ANIM = 0x6735, + SMSG_GAMEOBJECT_PAGETEXT = 0x2925, + SMSG_GAMEOBJECT_QUERY_RESPONSE = 0x0915, + SMSG_GAMEOBJECT_RESET_STATE = 0x2A16, + SMSG_GAMESPEED_SET = 0x4E34, + SMSG_GAMETIME_SET = 0x0014, + SMSG_GAMETIME_UPDATE = 0x4127, + SMSG_GAME_EVENT_DEBUG_LOG = 0x31A7, + SMSG_GAME_OBJECT_ACTIVATE_ANIM_KIT = 0x14A3, + SMSG_GMRESPONSE_DB_ERROR = 0x0006, + SMSG_GMRESPONSE_RECEIVED = 0x2E34, + SMSG_GMRESPONSE_STATUS_UPDATE = 0x0A04, + SMSG_GMTICKET_CREATE = 0x2107, + SMSG_GMTICKET_DELETETICKET = 0x6D17, + SMSG_GMTICKET_GETTICKET = 0x2C15, + SMSG_GMTICKET_SYSTEMSTATUS = 0x0D35, + SMSG_GMTICKET_UPDATETEXT = 0x6535, + SMSG_GM_MESSAGECHAT = 0x6434, + SMSG_GM_PLAYER_INFO = 0x4A15, + SMSG_GM_TICKET_STATUS_UPDATE = 0x2C25, + SMSG_GODMODE = 0x0405, + SMSG_GOSSIP_COMPLETE = 0x0806, + SMSG_GOSSIP_MESSAGE = 0x2035, + SMSG_GOSSIP_POI = 0x4316, + SMSG_GROUPACTION_THROTTLED = 0x6524, + SMSG_GROUP_CANCEL = 0x4D25, + SMSG_GROUP_DECLINE = 0x6835, + SMSG_GROUP_DESTROYED = 0x2207, + SMSG_GROUP_INVITE = 0x31B2, + SMSG_GROUP_LIST = 0x4C24, + SMSG_GROUP_SET_LEADER = 0x0526, + SMSG_GROUP_SET_ROLE = 0x39A6, + SMSG_GROUP_UNINVITE = 0x0A07, + SMSG_GUILD_ACHIEVEMENT_DATA = 0x54B7, + SMSG_GUILD_ACHIEVEMENT_DELETED = 0x35A0, + SMSG_GUILD_ACHIEVEMENT_EARNED = 0x50B5, + SMSG_GUILD_ACHIEVEMENT_MEMBERS = 0x38A5, + SMSG_GUILD_BANK_LIST = 0x78A5, + SMSG_GUILD_BANK_LOG_QUERY_RESULT = 0x30B2, + SMSG_GUILD_BANK_MONEY_WITHDRAWN = 0x5DB4, + SMSG_GUILD_BANK_QUERY_TEXT_RESULT = 0x75A3, + SMSG_GUILD_CANCEL = 0x0000, + SMSG_GUILD_CHALLENGE_COMPLETED = 0x39A3, + SMSG_GUILD_CHALLENGE_UPDATED = 0x18B1, + SMSG_GUILD_CHANGE_NAME_RESULT = 0x3CB1, + SMSG_GUILD_COMMAND_RESULT = 0x7DB3, + SMSG_GUILD_COMMAND_RESULT_2 = 0x2707, + SMSG_GUILD_CRITERIA_DATA = 0x14B4, + SMSG_GUILD_CRITERIA_DELETED = 0x55B1, + SMSG_GUILD_DECLINE = 0x2C07, + SMSG_GUILD_EVENT = 0x0705, + SMSG_GUILD_EVENT_LOG_QUERY_RESULT = 0x10B2, + SMSG_GUILD_FLAGGED_FOR_RENAME = 0x30B6, + SMSG_GUILD_INVITE = 0x14A2, + SMSG_GUILD_INVITE_CANCEL = 0x0606, + SMSG_GUILD_KNOWN_RECIPES = 0x0000, + SMSG_GUILD_MAX_DAILY_XP = 0x79B5, + SMSG_GUILD_MEMBERS_FOR_RECIPE = 0x1CB7, + SMSG_GUILD_MEMBER_DAILY_RESET = 0x10A5, + SMSG_GUILD_MEMBER_RECIPES = 0x1CB0, + SMSG_GUILD_MEMBER_UPDATE_NOTE = 0x7CA0, + SMSG_GUILD_MOVE_COMPLETE = 0x11B2, + SMSG_GUILD_MOVE_STARTING = 0x70A4, + SMSG_GUILD_NEWS_DELETED = 0x74A7, + SMSG_GUILD_NEWS_UPDATE = 0x35A7, + SMSG_GUILD_PARTY_STATE_RESPONSE = 0x50A6, + SMSG_GUILD_PERMISSIONS_QUERY_RESULTS = 0x34A3, + SMSG_GUILD_QUERY_RESPONSE = 0x0E06, + SMSG_GUILD_RANK = 0x30B4, + SMSG_GUILD_RANKS_UPDATE = 0x5DA0, + SMSG_GUILD_RECIPES = 0x10B3, + SMSG_GUILD_RENAMED = 0x74A6, + SMSG_GUILD_REPUTATION_REACTION_CHANGED = 0x74B0, + SMSG_GUILD_REPUTATION_WEEKLY_CAP = 0x30B7, + SMSG_GUILD_RESET = 0x1CB5, + SMSG_GUILD_REWARDS_LIST = 0x1DB0, + SMSG_GUILD_ROSTER = 0x3DA3, + SMSG_GUILD_SET_NOTE = 0x0000, + SMSG_GUILD_TRADESKILL_UPDATE = 0x0000, + SMSG_GUILD_UPDATE_ROSTER = 0x18B0, + SMSG_GUILD_XP = 0x3DB0, + SMSG_GUILD_XP_GAIN = 0x14A1, + SMSG_GUILD_XP_UPDATE = 0x0000, + SMSG_HEALTH_UPDATE = 0x4734, + SMSG_HIGHEST_THREAT_UPDATE = 0x4104, + SMSG_HOTFIX_INFO = 0x19B5, + SMSG_HOTFIX_NOTIFY = 0x55A7, + SMSG_INITIALIZE_FACTIONS = 0x4634, + SMSG_INITIAL_SPELLS = 0x0104, + SMSG_INIT_CURRENCY = 0x15A5, + SMSG_INIT_WORLD_STATES = 0x4C15, + SMSG_INSPECT = 0x0000, + SMSG_INSPECT_HONOR_STATS = 0x79A5, + SMSG_INSPECT_RATED_BG_STATS = 0x19A5, + SMSG_INSPECT_RESULTS_UPDATE = 0x0C14, + SMSG_INSPECT_TALENT = 0x4014, + SMSG_INSTANCE_LOCK_WARNING_QUERY = 0x4F17, + SMSG_INSTANCE_RESET = 0x6F05, + SMSG_INSTANCE_RESET_FAILED = 0x4725, + SMSG_INSTANCE_SAVE_CREATED = 0x0124, + SMSG_INVALIDATE_DANCE = 0x0E27, + SMSG_INVALIDATE_PLAYER = 0x6325, + SMSG_INVALID_PROMOTION_CODE = 0x6F25, + SMSG_INVENTORY_CHANGE_FAILURE = 0x2236, + SMSG_ITEM_ADD_PASSIVE = 0x7CB4, + SMSG_ITEM_COOLDOWN = 0x4D14, + SMSG_ITEM_ENCHANT_TIME_UPDATE = 0x0F27, + SMSG_ITEM_EXPIRE_PURCHASE_REFUND = 0x1CA0, + SMSG_ITEM_PUSH_RESULT = 0x0E15, + SMSG_ITEM_REFUND_INFO_RESPONSE = 0x15A3, + SMSG_ITEM_REFUND_RESULT = 0x5DB1, + SMSG_ITEM_REMOVE_PASSIVE = 0x39A1, + SMSG_ITEM_SEND_PASSIVE = 0x70B1, + SMSG_ITEM_TEXT_QUERY_RESPONSE = 0x2725, + SMSG_ITEM_TIME_UPDATE = 0x2407, + SMSG_JOINED_BATTLEGROUND_QUEUE = 0x0000, + SMSG_KICK_REASON = 0x0000, + SMSG_LEARNED_DANCE_MOVES = 0x0E05, + SMSG_LEARNED_SPELL = 0x58A2, + SMSG_LEVELUP_INFO = 0x0435, + SMSG_LFG_BOOT_PROPOSAL_UPDATE = 0x0F05, + SMSG_LFG_DISABLED = 0x0815, + SMSG_LFG_JOIN_RESULT = 0x38B6, + SMSG_LFG_OFFER_CONTINUE = 0x6B27, + SMSG_LFG_OPEN_FROM_GOSSIP = 0x0000, + SMSG_LFG_PARTY_INFO = 0x2325, + SMSG_LFG_PLAYER_INFO = 0x4B36, + SMSG_LFG_PLAYER_REWARD = 0x6834, + SMSG_LFG_PROPOSAL_UPDATE = 0x7DA6, + SMSG_LFG_QUEUE_STATUS = 0x78B4, + SMSG_LFG_ROLE_CHECK_UPDATE = 0x0336, + SMSG_LFG_ROLE_CHOSEN = 0x6A26, + SMSG_LFG_SLOT_INVALID = 0x54B5, + SMSG_LFG_TELEPORT_DENIED = 0x0E14, + SMSG_LFG_UPDATE_LIST = 0x0000, + SMSG_LFG_UPDATE_SEARCH = 0x54A1, + SMSG_LFG_UPDATE_STATUS = 0x31A4, + SMSG_LFG_UPDATE_STATUS_NONE = 0x7CA1, + SMSG_LF_GUILD_APPLICANT_LIST_UPDATED = 0x10A4, + SMSG_LF_GUILD_APPLICATIONS_LIST_CHANGED = 0x71A5, + SMSG_LF_GUILD_BROWSE_UPDATED = 0x1DA3, + SMSG_LF_GUILD_COMMAND_RESULT = 0x54A6, + SMSG_LF_GUILD_MEMBERSHIP_LIST_UPDATED = 0x1CA5, + SMSG_LF_GUILD_POST_UPDATED = 0x35B7, + SMSG_LF_GUILD_RECRUIT_LIST_UPDATED = 0x1CB2, + SMSG_LIST_INVENTORY = 0x7CB0, + SMSG_LOAD_CUF_PROFILES = 0x50B1, + SMSG_LOGIN_SETTIMESPEED = 0x4D15, + SMSG_LOGIN_VERIFY_WORLD = 0x2005, + SMSG_LOGOUT_CANCEL_ACK = 0x6514, + SMSG_LOGOUT_COMPLETE = 0x2137, + SMSG_LOGOUT_RESPONSE = 0x0524, + SMSG_LOG_XPGAIN = 0x4514, + SMSG_LOOT_ALL_PASSED = 0x6237, + SMSG_LOOT_CLEAR_MONEY = 0x2B37, + SMSG_LOOT_CONTENTS = 0x11B1, + SMSG_LOOT_ITEM_NOTIFY = 0x6D15, + SMSG_LOOT_LIST = 0x6807, + SMSG_LOOT_MASTER_LIST = 0x0325, + SMSG_LOOT_MONEY_NOTIFY = 0x2836, + SMSG_LOOT_RELEASE_RESPONSE = 0x6D25, + SMSG_LOOT_REMOVED = 0x6817, + SMSG_LOOT_RESPONSE = 0x4C16, + SMSG_LOOT_ROLL = 0x6507, + SMSG_LOOT_ROLL_WON = 0x6617, + SMSG_LOOT_SLOT_CHANGED = 0x2935, + SMSG_LOOT_START_ROLL = 0x2227, + SMSG_MAIL_LIST_RESULT = 0x4217, + SMSG_MAP_OBJ_EVENTS = 0x54B2, + SMSG_MEETINGSTONE_COMPLETE = 0x0000, + SMSG_MEETINGSTONE_IN_PROGRESS = 0x2D35, + SMSG_MEETINGSTONE_MEMBER_ADDED = 0x0000, + SMSG_MEETINGSTONE_SETQUEUE = 0x0000, + SMSG_MESSAGECHAT = 0x2026, + SMSG_MESSAGE_BOX = 0x30A1, + SMSG_MINIGAME_SETUP = 0x6727, + SMSG_MINIGAME_STATE = 0x2E17, + SMSG_MIRRORIMAGE_DATA = 0x2634, + SMSG_MISSILE_CANCEL = 0x3DB4, + SMSG_MODIFY_COOLDOWN = 0x6016, + SMSG_MONEY_NOTIFY = 0x55B6, + SMSG_MONSTER_MOVE = 0x6E17, + SMSG_MONSTER_MOVE_TRANSPORT = 0x2004, + SMSG_MOTD = 0x0A35, + SMSG_MOUNTRESULT = 0x2225, + SMSG_MOUNTSPECIAL_ANIM = 0x0217, + SMSG_MOVE_COLLISION_DISABLE = 0x31B0, + SMSG_MOVE_COLLISION_ENABLE = 0x11A7, + SMSG_MOVE_FEATHER_FALL = 0x79B0, + SMSG_MOVE_GRAVITY_DISABLE = 0x75B2, + SMSG_MOVE_GRAVITY_ENABLE = 0x30B3, + SMSG_MOVE_KNOCK_BACK = 0x5CB4, + SMSG_MOVE_LAND_WALK = 0x34B7, + SMSG_MOVE_NORMAL_FALL = 0x51B6, + SMSG_MOVE_ROOT = 0x7DA0, + SMSG_MOVE_SET_ACTIVE_MOVER = 0x11B3, + SMSG_MOVE_SET_CAN_FLY = 0x3DA1, + SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY = 0x59A2, + SMSG_MOVE_SET_COLLISION_HEIGHT = 0x11B0, + SMSG_MOVE_SET_COMPOUND_STATE = 0x75A0, + SMSG_MOVE_SET_FLIGHT_BACK_SPEED = 0x30A2, + SMSG_MOVE_SET_FLIGHT_SPEED = 0x71A6, + SMSG_MOVE_SET_HOVER = 0x5CB3, + SMSG_MOVE_SET_PITCH_RATE = 0x75B0, + SMSG_MOVE_SET_RUN_BACK_SPEED = 0x71B1, + SMSG_MOVE_SET_RUN_SPEED = 0x3DB5, + SMSG_MOVE_SET_SWIM_BACK_SPEED = 0x5CA6, + SMSG_MOVE_SET_SWIM_SPEED = 0x15A7, + SMSG_MOVE_SET_TURN_RATE = 0x30A5, + SMSG_MOVE_SET_VEHICLE_REC_ID = 0x0000, + SMSG_MOVE_SET_WALK_IN_AIR = 0x0000, + SMSG_MOVE_SET_WALK_SPEED = 0x1DA4, + SMSG_MOVE_UNROOT = 0x7DB4, + SMSG_MOVE_UNSET_CAN_FLY = 0x15A2, + SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY = 0x7DB2, + SMSG_MOVE_UNSET_HOVER = 0x51B3, + SMSG_MOVE_UNSET_WALK_IN_AIR = 0x0000, + SMSG_MOVE_UPDATE_COLLISION_HEIGHT = 0x59A3, + SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED = 0x74A0, + SMSG_MOVE_UPDATE_FLIGHT_SPEED = 0x30B1, + SMSG_MOVE_UPDATE_KNOCK_BACK = 0x3DB2, + SMSG_MOVE_UPDATE_PITCH_RATE = 0x1DB5, + SMSG_MOVE_UPDATE_RUN_BACK_SPEED = 0x3DA6, + SMSG_MOVE_UPDATE_RUN_SPEED = 0x14A6, + SMSG_MOVE_UPDATE_SWIM_BACK_SPEED = 0x30B5, + SMSG_MOVE_UPDATE_SWIM_SPEED = 0x59B5, + SMSG_MOVE_UPDATE_TELEPORT = 0x50B2, + SMSG_MOVE_UPDATE_TURN_RATE = 0x5DA1, + SMSG_MOVE_UPDATE_WALK_SPEED = 0x54A2, + SMSG_MOVE_WATER_WALK = 0x75B1, + SMSG_MULTIPLE_PACKETS = 0x6736, + SMSG_NAME_QUERY_RESPONSE = 0x6E04, + SMSG_NEW_TAXI_PATH = 0x4B35, + SMSG_NEW_WORLD = 0x79B1, + SMSG_NEW_WORLD_ABORT = 0x14B7, + SMSG_NOTIFICATION = 0x14A0, + SMSG_NOTIFY_DANCE = 0x4904, + SMSG_NOTIFY_DEST_LOC_SPELL_CAST = 0x6204, + SMSG_NPC_TEXT_UPDATE = 0x4436, + SMSG_NPC_WONT_TALK = 0x0000, + SMSG_OFFER_PETITION_ERROR = 0x2716, + SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA = 0x4D34, + SMSG_OPEN_CONTAINER = 0x4714, + SMSG_OPEN_LFG_DUNGEON_FINDER = 0x2C37, + SMSG_OVERRIDE_LIGHT = 0x4225, + SMSG_PAGE_TEXT_QUERY_RESPONSE = 0x2B14, + SMSG_PARTYKILLLOG = 0x4937, + SMSG_PARTY_COMMAND_RESULT = 0x6E07, + SMSG_PARTY_MEMBER_STATS = 0x2104, + SMSG_PARTY_MEMBER_STATS_FULL = 0x0215, + SMSG_PAUSE_MIRROR_TIMER = 0x4015, + SMSG_PERIODICAURALOG = 0x0416, + SMSG_PETGODMODE = 0x2E36, + SMSG_PETITION_ALREADY_SIGNED = 0x5DA3, + SMSG_PETITION_QUERY_RESPONSE = 0x4B37, + SMSG_PETITION_SHOWLIST = 0x6405, + SMSG_PETITION_SHOW_SIGNATURES = 0x0716, + SMSG_PETITION_SIGN_RESULTS = 0x6217, + SMSG_PET_ACTION_FEEDBACK = 0x0807, + SMSG_PET_ACTION_SOUND = 0x4324, + SMSG_PET_ADDED = 0x3CA5, + SMSG_PET_BROKEN = 0x2E27, + SMSG_PET_CAST_FAILED = 0x2B15, + SMSG_PET_DISMISS_SOUND = 0x2B05, + SMSG_PET_GUIDS = 0x2D26, + SMSG_PET_LEARNED_SPELL = 0x0507, + SMSG_PET_MODE = 0x2235, + SMSG_PET_NAME_INVALID = 0x6007, + SMSG_PET_NAME_QUERY_RESPONSE = 0x4C37, + SMSG_PET_REMOVED_SPELL = 0x6A04, + SMSG_PET_RENAMEABLE = 0x2B27, + SMSG_PET_SLOT_UPDATED = 0x51A3, + SMSG_PET_SPELLS = 0x4114, + SMSG_PET_TAME_FAILURE = 0x6B24, + SMSG_PET_UPDATE_COMBO_POINTS = 0x4325, + SMSG_PLAYED_TIME = 0x6037, + SMSG_PLAYERBINDERROR = 0x6A24, + SMSG_PLAYERBOUND = 0x2516, + SMSG_PLAYER_DIFFICULTY_CHANGE = 0x2217, + SMSG_PLAYER_MOVE = 0x79A2, + SMSG_PLAYER_SKINNED = 0x0116, + SMSG_PLAYER_UNK_DEAD_ALIVE = 0x0000, + SMSG_PLAYER_VEHICLE_DATA = 0x4115, + SMSG_PLAY_DANCE = 0x4704, + SMSG_PLAY_MUSIC = 0x4B06, + SMSG_PLAY_OBJECT_SOUND = 0x2635, + SMSG_PLAY_ONE_SHOT_ANIM_KIT = 0x4A35, + SMSG_PLAY_SOUND = 0x2134, + SMSG_PLAY_SPELL_VISUAL = 0x10B1, + SMSG_PLAY_SPELL_VISUAL_KIT = 0x55A5, + SMSG_PLAY_TIME_WARNING = 0x4814, + SMSG_PONG = 0x4D42, + SMSG_POWER_UPDATE = 0x4A07, + SMSG_PRE_RESURRECT = 0x6C36, + SMSG_PROCRESIST = 0x0426, + SMSG_PROPOSE_LEVEL_GRANT = 0x6114, + SMSG_PUREMOUNT_CANCELLED_OBSOLETE = 0x0000, + SMSG_PVP_CREDIT = 0x6015, + SMSG_PVP_LOG_DATA = 0x5CB2, + SMSG_PVP_OPTIONS_ENABLED = 0x50A1, + SMSG_QUERY_QUESTS_COMPLETED_RESPONSE = 0x6314, + SMSG_QUERY_TIME_RESPONSE = 0x2124, + SMSG_QUESTGIVER_OFFER_REWARD = 0x2427, + SMSG_QUESTGIVER_QUEST_COMPLETE = 0x55A4, + SMSG_QUESTGIVER_QUEST_DETAILS = 0x2425, + SMSG_QUESTGIVER_QUEST_FAILED = 0x4236, + SMSG_QUESTGIVER_QUEST_INVALID = 0x4016, + SMSG_QUESTGIVER_QUEST_LIST = 0x0134, + SMSG_QUESTGIVER_REQUEST_ITEMS = 0x6236, + SMSG_QUESTGIVER_STATUS = 0x2115, + SMSG_QUESTGIVER_STATUS_MULTIPLE = 0x4F25, + SMSG_QUESTLOG_FULL = 0x0E36, + SMSG_QUESTUPDATE_ADD_ITEM = 0x0000, + SMSG_QUESTUPDATE_ADD_KILL = 0x0D27, + SMSG_QUESTUPDATE_ADD_PVP_KILL = 0x4416, + SMSG_QUESTUPDATE_COMPLETE = 0x2937, + SMSG_QUESTUPDATE_FAILED = 0x6324, + SMSG_QUESTUPDATE_FAILEDTIMER = 0x6427, + SMSG_QUEST_NPC_QUERY_RESPONSE = 0x75A1, + SMSG_QUEST_CONFIRM_ACCEPT = 0x6F07, + SMSG_QUEST_FORCE_REMOVE = 0x6605, + SMSG_QUEST_POI_QUERY_RESPONSE = 0x6304, + SMSG_QUEST_QUERY_RESPONSE = 0x6936, + SMSG_RAID_GROUP_ONLY = 0x0837, + SMSG_RAID_INSTANCE_INFO = 0x6626, + SMSG_RAID_INSTANCE_MESSAGE = 0x6E15, + SMSG_RAID_MARKERS_CHANGED = 0x10A1, + SMSG_RAID_READY_CHECK_THROTTLED_ERROR = 0x2607, + SMSG_RAID_SUMMON_FAILED = 0x18B6, + SMSG_RANDOMIZE_CHAR_NAME = 0x38B1, + SMSG_RATED_BG_RATING = 0x15A1, + SMSG_RATED_BG_STATS = 0x34A1, + SMSG_READ_ITEM_FAILED = 0x0F16, + SMSG_READ_ITEM_OK = 0x2605, + SMSG_REALM_SPLIT = 0x2714, + SMSG_REAL_GROUP_UPDATE = 0x0F34, + SMSG_RECEIVED_MAIL = 0x2924, + SMSG_REDIRECT_CLIENT = 0x0942, + SMSG_REFER_A_FRIEND_EXPIRED = 0x4934, + SMSG_REFER_A_FRIEND_FAILURE = 0x2037, + SMSG_REFORGE_RESULT = 0x58A4, + SMSG_REMOVED_SPELL = 0x4804, + SMSG_REPORT_PVP_AFK_RESULT = 0x2D06, + SMSG_REQUEST_CEMETERY_LIST_RESPONSE = 0x30A7, + SMSG_REQUEST_PVP_REWARDS_RESPONSE = 0x5DA4, + SMSG_RESEARCH_COMPLETE = 0x35A6, + SMSG_RESEARCH_SETUP_HISTORY = 0x10B6, + SMSG_RESET_COMPRESSION_CONTEXT = 0x0142, + SMSG_RESET_FAILED_NOTIFY = 0x4616, + SMSG_RESISTLOG = 0x0000, + SMSG_RESPOND_INSPECT_ACHIEVEMENTS = 0x15B0, + SMSG_RESURRECT_REQUEST = 0x2905, + SMSG_RESYNC_RUNES = 0x6224, + SMSG_ROLE_POLL_BEGIN = 0x70B0, + SMSG_RWHOIS = 0x2437, + SMSG_SELL_ITEM = 0x6105, + SMSG_SEND_MAIL_RESULT = 0x4927, + SMSG_SEND_UNLEARN_SPELLS = 0x4E25, + SMSG_SERVERTIME = 0x6327, + SMSG_SERVER_FIRST_ACHIEVEMENT = 0x6424, + SMSG_SERVER_INFO_RESPONSE = 0x74B5, + SMSG_SERVER_MESSAGE = 0x6C04, + SMSG_SERVER_PERF = 0x74B6, + SMSG_SET_AI_ANIM_KIT = 0x0000, + SMSG_SET_DF_FAST_LAUNCH_RESULT = 0x35B6, + SMSG_SET_FACTION_ATWAR = 0x4216, + SMSG_SET_FACTION_STANDING = 0x0126, + SMSG_SET_FACTION_VISIBLE = 0x2525, + SMSG_SET_FLAT_SPELL_MODIFIER = 0x2834, + SMSG_SET_FORCED_REACTIONS = 0x4615, + SMSG_SET_MELEE_ANIM_KIT = 0x0000, + SMSG_SET_MOVEMENT_ANIM_KIT = 0x0000, + SMSG_SET_PCT_SPELL_MODIFIER = 0x0224, + SMSG_SET_PHASE_SHIFT = 0x70A0, + SMSG_SET_PLAYER_DECLINED_NAMES_RESULT = 0x2B25, + SMSG_SET_PLAY_HOVER_ANIM = 0x30A6, + SMSG_SET_PROFICIENCY = 0x6207, + SMSG_SET_PROJECTILE_POSITION = 0x2616, + SMSG_SHOWTAXINODES = 0x2A36, + SMSG_SHOW_BANK = 0x2627, + SMSG_SHOW_MAILBOX = 0x2524, + SMSG_SHOW_RATINGS = 0x11B4, + SMSG_SOCKET_GEMS_RESULT = 0x6014, + SMSG_SOR_START_EXPERIENCE_INCOMPLETE = 0x7CA7, + SMSG_SPELLBREAKLOG = 0x6B17, + SMSG_SPELLDAMAGESHIELD = 0x2927, + SMSG_SPELLDISPELLOG = 0x4516, + SMSG_SPELLENERGIZELOG = 0x0414, + SMSG_SPELLHEALLOG = 0x2816, + SMSG_SPELLINSTAKILLLOG = 0x6216, + SMSG_SPELLINTERRUPTLOG = 0x1DA7, + SMSG_SPELLLOGEXECUTE = 0x0626, + SMSG_SPELLLOGMISS = 0x0625, + SMSG_SPELLNONMELEEDAMAGELOG = 0x4315, + SMSG_SPELLORDAMAGE_IMMUNE = 0x4507, + SMSG_SPELLSTEALLOG = 0x4E26, + SMSG_SPELL_CATEGORY_COOLDOWN = 0x71B6, + SMSG_SPELL_COOLDOWN = 0x4B16, + SMSG_SPELL_DELAYED = 0x0715, + SMSG_SPELL_FAILED_OTHER = 0x0C34, + SMSG_SPELL_FAILURE = 0x4535, + SMSG_SPELL_GO = 0x6E16, + SMSG_SPELL_START = 0x6415, + SMSG_SPELL_UPDATE_CHAIN_TARGETS = 0x6006, + SMSG_SPIRIT_HEALER_CONFIRM = 0x4917, + SMSG_SPLINE_MOVE_COLLISION_DISABLE = 0x35B1, + SMSG_SPLINE_MOVE_COLLISION_ENABLE = 0x3CB0, + SMSG_SPLINE_MOVE_GRAVITY_DISABLE = 0x5DB5, + SMSG_SPLINE_MOVE_GRAVITY_ENABLE = 0x3CA6, + SMSG_SPLINE_MOVE_ROOT = 0x51B4, + SMSG_SPLINE_MOVE_SET_ANIM = 0x4335, + SMSG_SPLINE_MOVE_SET_FEATHER_FALL = 0x3DA5, + SMSG_SPLINE_MOVE_SET_FLIGHT_BACK_SPEED = 0x38B3, + SMSG_SPLINE_MOVE_SET_FLIGHT_SPEED = 0x39A0, + SMSG_SPLINE_MOVE_SET_FLYING = 0x31B5, + SMSG_SPLINE_MOVE_SET_HOVER = 0x14B6, + SMSG_SPLINE_MOVE_SET_LAND_WALK = 0x3DA7, + SMSG_SPLINE_MOVE_SET_NORMAL_FALL = 0x38B2, + SMSG_SPLINE_MOVE_SET_PITCH_RATE = 0x14B0, + SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED = 0x3DB3, + SMSG_SPLINE_MOVE_SET_RUN_MODE = 0x75A7, + SMSG_SPLINE_MOVE_SET_RUN_SPEED = 0x51B7, + SMSG_SPLINE_MOVE_SET_SWIM_BACK_SPEED = 0x59A1, + SMSG_SPLINE_MOVE_SET_SWIM_SPEED = 0x39A4, + SMSG_SPLINE_MOVE_SET_TURN_RATE = 0x78B5, + SMSG_SPLINE_MOVE_SET_WALK_MODE = 0x54B6, + SMSG_SPLINE_MOVE_SET_WALK_SPEED = 0x34A5, + SMSG_SPLINE_MOVE_SET_WATER_WALK = 0x50A2, + SMSG_SPLINE_MOVE_START_SWIM = 0x31A5, + SMSG_SPLINE_MOVE_STOP_SWIM = 0x1DA2, + SMSG_SPLINE_MOVE_UNROOT = 0x75B6, + SMSG_SPLINE_MOVE_UNSET_FLYING = 0x58A6, + SMSG_SPLINE_MOVE_UNSET_HOVER = 0x7DA5, + SMSG_SPLINE_MOVE_WATER_WALK = 0x50A2, + SMSG_STABLE_RESULT = 0x2204, + SMSG_STANDSTATE_UPDATE = 0x6F04, + SMSG_START_MIRROR_TIMER = 0x6824, + SMSG_START_TIMER = 0x59A5, + SMSG_STOP_DANCE = 0x4637, + SMSG_STOP_MIRROR_TIMER = 0x0B06, + SMSG_STREAMING_MOVIE = 0x15B7, + SMSG_SUMMON_CANCEL = 0x0B34, + SMSG_SUMMON_REQUEST = 0x2A07, + SMSG_SUPERCEDED_SPELL = 0x35B0, + SMSG_SUPPRESS_NPC_GREETINGS = 0x74B1, + SMSG_SUSPEND_COMMS = 0x4140, + SMSG_SUSPEND_TOKEN_RESPONSE = 0x14B1, + SMSG_TALENTS_ERROR = 0x0916, + SMSG_TALENTS_INFO = 0x6F26, + SMSG_TALENTS_INVOLUNTARILY_RESET = 0x2C27, + SMSG_TAXINODE_STATUS = 0x2936, + SMSG_TEST_DROP_RATE_RESULT = 0x6816, + SMSG_TEXT_EMOTE = 0x0B05, + SMSG_THREAT_CLEAR = 0x6437, + SMSG_THREAT_REMOVE = 0x2E05, + SMSG_THREAT_UPDATE = 0x4735, + SMSG_TIME_ADJUSTMENT = 0x79B7, + SMSG_TIME_SYNC_REQ = 0x3CA4, + SMSG_TITLE_EARNED = 0x2426, + SMSG_TOGGLE_XP_GAIN = 0x6704, + SMSG_TOTEM_CREATED = 0x2414, + SMSG_TRADE_STATUS = 0x5CA3, + SMSG_TRADE_STATUS_EXTENDED = 0x70A2, + SMSG_TRAINER_BUY_FAILED = 0x0004, + SMSG_TRAINER_BUY_SUCCEEDED = 0x6A05, + SMSG_TRAINER_LIST = 0x4414, + SMSG_TRANSFER_ABORTED = 0x0537, + SMSG_TRANSFER_PENDING = 0x18A6, + SMSG_TRIGGER_CINEMATIC = 0x6C27, + SMSG_TRIGGER_MOVIE = 0x4625, + SMSG_TURN_IN_PETITION_RESULTS = 0x0F07, + SMSG_TUTORIAL_FLAGS = 0x0B35, + SMSG_UNIT_HEALTH_FREQUENT = 0x2C26, + SMSG_UNIT_SPELLCAST_START = 0x2517, + SMSG_UPDATE_ACCOUNT_DATA = 0x6837, + SMSG_UPDATE_ACCOUNT_DATA_COMPLETE = 0x2015, + SMSG_UPDATE_COMBO_POINTS = 0x6B34, + SMSG_UPDATE_CURRENCY = 0x59B0, + SMSG_UPDATE_CURRENCY_WEEK_LIMIT = 0x70A7, + SMSG_UPDATE_DUNGEON_ENCOUNTER_FOR_LOOT = 0x3CB5, + SMSG_UPDATE_INSTANCE_ENCOUNTER_UNIT = 0x4007, + SMSG_UPDATE_INSTANCE_OWNERSHIP = 0x4915, + SMSG_UPDATE_LAST_INSTANCE = 0x0437, + SMSG_UPDATE_OBJECT = 0x4715, + SMSG_UPDATE_SERVER_PLAYER_POSITION = 0x74A3, + SMSG_UPDATE_WORLD_STATE = 0x4816, + SMSG_USERLIST_ADD = 0x0F37, + SMSG_USERLIST_REMOVE = 0x2006, + SMSG_USERLIST_UPDATE = 0x0135, + SMSG_VOICESESSION_FULL = 0x6225, + SMSG_VOICE_CHAT_STATUS = 0x0F15, + SMSG_VOICE_PARENTAL_CONTROLS = 0x0534, + SMSG_VOICE_SESSION_LEAVE = 0x2A24, + SMSG_VOICE_SESSION_ROSTER_UPDATE = 0x2A17, + SMSG_VOICE_SET_TALKER_MUTED = 0x6E35, + SMSG_VOID_ITEM_SWAP_RESPONSE = 0x78A2, + SMSG_VOID_STORAGE_CONTENTS = 0x75B4, + SMSG_VOID_STORAGE_FAILED = 0x18A7, + SMSG_VOID_STORAGE_TRANSFER_CHANGES = 0x51A6, + SMSG_VOID_TRANSFER_RESULT = 0x1DA6, + SMSG_WAIT_QUEUE_FINISH = 0x75B7, + SMSG_WAIT_QUEUE_UPDATE = 0x58A1, + SMSG_WARDEN_DATA = 0x31A0, + SMSG_WARGAME_CHECK_ENTRY = 0x3DA4, + SMSG_WARGAME_REQUEST_SENT = 0x59B2, + SMSG_WEATHER = 0x2904, + SMSG_WEEKLY_LAST_RESET = 0x50A5, + SMSG_WEEKLY_RESET_CURRENCY = 0x3CA1, + SMSG_WEEKLY_SPELL_USAGE = 0x39B7, + SMSG_WEEKLY_SPELL_USAGE_UPDATE = 0x11B5, + SMSG_WHO = 0x6907, + SMSG_WHOIS = 0x6917, + SMSG_WORLD_SERVER_INFO = 0x31A2, + SMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4A14, + SMSG_XP_GAIN_ABORTED = 0x50B4, + SMSG_ZONE_UNDER_ATTACK = 0x0A06, }; /// Player state @@ -1362,6 +1397,9 @@ enum PacketProcessing class WorldSession; class WorldPacket; +class WorldSession; + +typedef void(WorldSession::*pOpcodeHandler)(WorldPacket& recvPacket); #if defined(__GNUC__) #pragma pack(1) @@ -1371,13 +1409,49 @@ class WorldPacket; struct OpcodeHandler { - char const* name; - SessionStatus status; - PacketProcessing packetProcessing; - void (WorldSession::*handler)(WorldPacket& recvPacket); + OpcodeHandler() {} + OpcodeHandler(char const* _name, SessionStatus _status, PacketProcessing _processing, pOpcodeHandler _handler) + : Handler(_handler), Name(_name), Status(_status), ProcessingPlace(_processing) {} + + pOpcodeHandler Handler; + char const* Name; + SessionStatus Status; + PacketProcessing ProcessingPlace; }; -extern OpcodeHandler opcodeTable[NUM_MSG_TYPES]; +class OpcodeTable +{ + public: + OpcodeTable() + { + memset(_internalTable, 0, sizeof(_internalTable)); + } + + ~OpcodeTable() + { + for (uint16 i = 0; i < NUM_OPCODE_HANDLERS; ++i) + delete _internalTable[i]; + } + + void Initialize(); + + OpcodeHandler const* operator[](uint32 index) const + { + return _internalTable[index]; + } + + private: + template<bool isInValidRange, bool isNonZero> + void ValidateAndSetOpcode(uint16 opcode, char const* name, SessionStatus status, PacketProcessing processing, pOpcodeHandler handler); + + // Prevent copying this structure + OpcodeTable(OpcodeTable const&); + OpcodeTable& operator=(OpcodeTable const&); + + OpcodeHandler* _internalTable[NUM_OPCODE_HANDLERS]; +}; + +extern OpcodeTable opcodeTable; #if defined(__GNUC__) #pragma pack() @@ -1385,18 +1459,30 @@ extern OpcodeHandler opcodeTable[NUM_MSG_TYPES]; #pragma pack(pop) #endif -/// Lookup opcode name for human understandable logging -inline const char* LookupOpcodeName(uint16 id) -{ - if (id >= NUM_MSG_TYPES) - return "Received unknown opcode, it's more than max!"; - return opcodeTable[id].name; -} +void InitOpcodes(); -inline std::string GetOpcodeNameForLogging(uint16 opcode) +/// Lookup opcode name for human understandable logging +inline std::string GetOpcodeNameForLogging(Opcodes id) { + uint32 opcode = uint32(id); std::ostringstream ss; - ss << '[' << LookupOpcodeName(opcode) << " 0x" << std::hex << std::uppercase << opcode << std::nouppercase << " (" << std::dec << opcode << ")]"; + ss << '['; + + if (id < UNKNOWN_OPCODE) + { + if (OpcodeHandler const* handler = opcodeTable[uint32(id) & 0x7FFF]) + { + ss << handler->Name; + if (opcode & COMPRESSED_OPCODE_MASK) + ss << "_COMPRESSED"; + } + else + ss << "UNKNOWN OPCODE"; + } + else + ss << "INVALID OPCODE"; + + ss << " 0x" << std::hex << std::uppercase << opcode << std::nouppercase << " (" << std::dec << opcode << ")]"; return ss.str(); } diff --git a/src/server/game/Server/Protocol/PacketLog.cpp b/src/server/game/Server/Protocol/PacketLog.cpp index 23dfb3538bc..a905b01c73c 100644 --- a/src/server/game/Server/Protocol/PacketLog.cpp +++ b/src/server/game/Server/Protocol/PacketLog.cpp @@ -78,7 +78,7 @@ void PacketLog::Initialize() header.Signature[0] = 'P'; header.Signature[1] = 'K'; header.Signature[2] = 'T'; header.FormatVersion = 0x0301; header.SnifferId = 'T'; - header.Build = 12340; + header.Build = 15595; header.Locale[0] = 'e'; header.Locale[1] = 'n'; header.Locale[2] = 'U'; header.Locale[3] = 'S'; std::memset(header.SessionKey, 0, sizeof(header.SessionKey)); header.SniffStartUnixtime = time(NULL); diff --git a/src/server/game/Server/WorldPacket.cpp b/src/server/game/Server/WorldPacket.cpp new file mode 100644 index 00000000000..0658973f320 --- /dev/null +++ b/src/server/game/Server/WorldPacket.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <zlib.h> +#include "WorldPacket.h" +#include "World.h" + +//! Compresses packet in place +void WorldPacket::Compress(z_stream* compressionStream) +{ + Opcodes uncompressedOpcode = GetOpcode(); + if (uncompressedOpcode & COMPRESSED_OPCODE_MASK) + { + TC_LOG_ERROR("network", "Packet with opcode 0x%04X is already compressed!", uncompressedOpcode); + return; + } + + Opcodes opcode = Opcodes(uncompressedOpcode | COMPRESSED_OPCODE_MASK); + uint32 size = wpos(); + uint32 destsize = compressBound(size); + + std::vector<uint8> storage(destsize); + + _compressionStream = compressionStream; + Compress(static_cast<void*>(&storage[0]), &destsize, static_cast<const void*>(contents()), size); + if (destsize == 0) + return; + + clear(); + reserve(destsize + sizeof(uint32)); + *this << uint32(size); + append(&storage[0], destsize); + SetOpcode(opcode); + TC_LOG_INFO("network", "%s (len %u) successfully compressed to %04X (len %u)", GetOpcodeNameForLogging(uncompressedOpcode).c_str(), size, opcode, destsize); +} + +//! Compresses another packet and stores it in self (source left intact) +void WorldPacket::Compress(z_stream* compressionStream, WorldPacket const* source) +{ + ASSERT(source != this); + + Opcodes uncompressedOpcode = source->GetOpcode(); + if (uncompressedOpcode & COMPRESSED_OPCODE_MASK) + { + TC_LOG_ERROR("network", "Packet with opcode 0x%04X is already compressed!", uncompressedOpcode); + return; + } + + Opcodes opcode = Opcodes(uncompressedOpcode | COMPRESSED_OPCODE_MASK); + uint32 size = source->size(); + uint32 destsize = compressBound(size); + + size_t sizePos = 0; + resize(destsize + sizeof(uint32)); + + _compressionStream = compressionStream; + Compress(static_cast<void*>(&_storage[0] + sizeof(uint32)), &destsize, static_cast<const void*>(source->contents()), size); + if (destsize == 0) + return; + + put<uint32>(sizePos, size); + resize(destsize + sizeof(uint32)); + + SetOpcode(opcode); + + TC_LOG_INFO("network", "%s (len %u) successfully compressed to %04X (len %u)", GetOpcodeNameForLogging(uncompressedOpcode).c_str(), size, opcode, destsize); +} + +void WorldPacket::Compress(void* dst, uint32 *dst_size, const void* src, int src_size) +{ + _compressionStream->next_out = (Bytef*)dst; + _compressionStream->avail_out = *dst_size; + _compressionStream->next_in = (Bytef*)src; + _compressionStream->avail_in = (uInt)src_size; + + int32 z_res = deflate(_compressionStream, Z_SYNC_FLUSH); + if (z_res != Z_OK) + { + TC_LOG_ERROR("network", "Can't compress packet (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); + *dst_size = 0; + return; + } + + if (_compressionStream->avail_in != 0) + { + TC_LOG_ERROR("network", "Can't compress packet (zlib: deflate not greedy)"); + *dst_size = 0; + return; + } + + *dst_size -= _compressionStream->avail_out; +} diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h new file mode 100644 index 00000000000..3e812621b48 --- /dev/null +++ b/src/server/game/Server/WorldPacket.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITYCORE_WORLDPACKET_H +#define TRINITYCORE_WORLDPACKET_H + +#include "Common.h" +#include "Opcodes.h" +#include "ByteBuffer.h" + +struct z_stream_s; + +class WorldPacket : public ByteBuffer +{ + public: + // just container for later use + WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE) + { + } + + explicit WorldPacket(Opcodes opcode, size_t res=200) : ByteBuffer(res), m_opcode(opcode) { } + + WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode) + { + } + + WorldPacket(WorldPacket const& right) : ByteBuffer(right), m_opcode(right.m_opcode) + { + } + + WorldPacket& operator=(WorldPacket const& right) + { + if (this != &right) + { + m_opcode = right.m_opcode; + ByteBuffer::operator =(right); + } + + return *this; + } + + void Initialize(Opcodes opcode, size_t newres=200) + { + clear(); + _storage.reserve(newres); + m_opcode = opcode; + } + + Opcodes GetOpcode() const { return m_opcode; } + void SetOpcode(Opcodes opcode) { m_opcode = opcode; } + void Compress(z_stream_s* compressionStream); + void Compress(z_stream_s* compressionStream, WorldPacket const* source); + + protected: + Opcodes m_opcode; + void Compress(void* dst, uint32 *dst_size, const void* src, int src_size); + z_stream_s* _compressionStream; +}; + +#endif diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 279e69a4267..227555c1dfa 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -21,6 +21,7 @@ */ #include "WorldSocket.h" +#include <zlib.h> #include "Config.h" #include "Common.h" #include "DatabaseEnv.h" @@ -46,7 +47,6 @@ #include "Transport.h" #include "WardenWin.h" #include "WardenMac.h" -#include "MoveSpline.h" namespace { @@ -56,14 +56,15 @@ std::string const DefaultPlayerName = "<none>"; bool MapSessionFilter::Process(WorldPacket* packet) { - OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; + Opcodes opcode = DropHighBytes(packet->GetOpcode()); + OpcodeHandler const* opHandle = opcodeTable[opcode]; //let's check if our opcode can be really processed in Map::Update() - if (opHandle.packetProcessing == PROCESS_INPLACE) + if (opHandle->ProcessingPlace == PROCESS_INPLACE) return true; //we do not process thread-unsafe packets - if (opHandle.packetProcessing == PROCESS_THREADUNSAFE) + if (opHandle->ProcessingPlace == PROCESS_THREADUNSAFE) return false; Player* player = m_pSession->GetPlayer(); @@ -78,13 +79,14 @@ bool MapSessionFilter::Process(WorldPacket* packet) //OR packet handler is not thread-safe! bool WorldSessionFilter::Process(WorldPacket* packet) { - OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; + Opcodes opcode = DropHighBytes(packet->GetOpcode()); + OpcodeHandler const* opHandle = opcodeTable[opcode]; //check if packet handler is supposed to be safe - if (opHandle.packetProcessing == PROCESS_INPLACE) + if (opHandle->ProcessingPlace == PROCESS_INPLACE) return true; //thread-unsafe packets should be processed in World::UpdateSessions() - if (opHandle.packetProcessing == PROCESS_THREADUNSAFE) + if (opHandle->ProcessingPlace == PROCESS_THREADUNSAFE) return true; //no player attached? -> our client! ^^ @@ -97,7 +99,7 @@ bool WorldSessionFilter::Process(WorldPacket* packet) } /// WorldSession constructor -WorldSession::WorldSession(uint32 id, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): +WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): m_muteTime(mute_time), m_timeOutTime(0), AntiDOS(this), @@ -106,6 +108,7 @@ WorldSession::WorldSession(uint32 id, std::shared_ptr<WorldSocket> sock, Account m_Socket(sock), _security(sec), _accountId(id), + _battlenetAccountId(battlenetAccountId), m_expansion(expansion), _warden(NULL), _logoutTime(0), @@ -119,6 +122,7 @@ WorldSession::WorldSession(uint32 id, std::shared_ptr<WorldSocket> sock, Account m_latency(0), m_clientTimeDelay(0), m_TutorialsChanged(false), + _filterAddonMessages(false), recruiterId(recruiter), isRecruiter(isARecruiter), _RBACData(NULL), @@ -136,6 +140,16 @@ WorldSession::WorldSession(uint32 id, std::shared_ptr<WorldSocket> sock, Account } InitializeQueryCallbackParameters(); + + _compressionStream = new z_stream(); + _compressionStream->zalloc = (alloc_func)NULL; + _compressionStream->zfree = (free_func)NULL; + _compressionStream->opaque = (voidpf)NULL; + _compressionStream->avail_in = 0; + _compressionStream->next_in = NULL; + int32 z_res = deflateInit(_compressionStream, sWorld->getIntConfig(CONFIG_COMPRESSION)); + if (z_res != Z_OK) + TC_LOG_ERROR("network", "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res)); } /// WorldSession destructor @@ -161,6 +175,12 @@ WorldSession::~WorldSession() delete packet; LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId()); // One-time query + + int32 z_res = deflateEnd(_compressionStream); + if (z_res != Z_OK && z_res != Z_DATA_ERROR) // Z_DATA_ERROR signals that internal state was BUSY + TC_LOG_ERROR("network", "Can't close packet compression stream (zlib: deflateEnd) Error code: %i (%s)", z_res, zError(z_res)); + + delete _compressionStream; } std::string const & WorldSession::GetPlayerName() const @@ -186,11 +206,32 @@ uint32 WorldSession::GetGuidLow() const } /// Send a packet to the client -void WorldSession::SendPacket(WorldPacket* packet) +void WorldSession::SendPacket(WorldPacket* packet, bool forced /*= false*/) { if (!m_Socket) return; + if (packet->GetOpcode() == NULL_OPCODE) + { + TC_LOG_ERROR("network.opcode", "Prevented sending of NULL_OPCODE to %s", GetPlayerInfo().c_str()); + return; + } + else if (packet->GetOpcode() == UNKNOWN_OPCODE) + { + TC_LOG_ERROR("network.opcode", "Prevented sending of UNKNOWN_OPCODE to %s", GetPlayerInfo().c_str()); + return; + } + + if (!forced) + { + OpcodeHandler const* handler = opcodeTable[packet->GetOpcode()]; + if (!handler || handler->Status == STATUS_UNHANDLED) + { + TC_LOG_ERROR("network.opcode", "Prevented sending disabled opcode %s to %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str(), GetPlayerInfo().c_str()); + return; + } + } + #ifdef TRINITY_DEBUG // Code for network use statistic static uint64 sendPacketCount = 0; @@ -281,107 +322,97 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) while (m_Socket && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { if (!AntiDOS.EvaluateOpcode(*packet, currentTime)) - { KickPlayer(); - } - else if (packet->GetOpcode() >= NUM_MSG_TYPES) - { - TC_LOG_ERROR("network.opcode", "Received non-existed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() - , GetPlayerInfo().c_str()); - sScriptMgr->OnUnknownPacketReceive(m_Socket, *packet); - } - else + + OpcodeHandler const* opHandle = opcodeTable[packet->GetOpcode()]; + try { - OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; - try + switch (opHandle->Status) { - switch (opHandle.status) - { - case STATUS_LOGGEDIN: - if (!_player) + case STATUS_LOGGEDIN: + if (!_player) + { + // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets + //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize + //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later. + if (!m_playerRecentlyLogout) { - // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets - //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize - //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later. - if (!m_playerRecentlyLogout) - { - //! Prevent infinite loop - if (!firstDelayedPacket) - firstDelayedPacket = packet; - //! Because checking a bool is faster than reallocating memory - deletePacket = false; - QueuePacket(packet); - //! Log + //! Prevent infinite loop + if (!firstDelayedPacket) + firstDelayedPacket = packet; + //! Because checking a bool is faster than reallocating memory + deletePacket = false; + QueuePacket(packet); + //! Log TC_LOG_DEBUG("network", "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. " "Player is currently not in world yet.", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()); - } - } - else if (_player->IsInWorld()) - { - sScriptMgr->OnPacketReceive(m_Socket, *packet); - (this->*opHandle.handler)(*packet); - LogUnprocessedTail(packet); } - // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer - break; - case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: - if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout - LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT", - "the player has not logged in yet and not recently logout"); - else - { - // not expected _player or must checked in packet handler - sScriptMgr->OnPacketReceive(m_Socket, *packet); - (this->*opHandle.handler)(*packet); - LogUnprocessedTail(packet); - } - break; - case STATUS_TRANSFER: - if (!_player) - LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet"); - else if (_player->IsInWorld()) - LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world"); - else - { - sScriptMgr->OnPacketReceive(m_Socket, *packet); - (this->*opHandle.handler)(*packet); - LogUnprocessedTail(packet); - } - break; - case STATUS_AUTHED: - // prevent cheating with skip queue wait - if (m_inQueue) - { - LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet"); - break; - } - - // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes - // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process. - if (packet->GetOpcode() == CMSG_CHAR_ENUM) - m_playerRecentlyLogout = false; - + } + else if (_player->IsInWorld()) + { + sScriptMgr->OnPacketReceive(m_Socket, *packet); + (this->*opHandle->Handler)(*packet); + LogUnprocessedTail(packet); + } + // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer + break; + case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: + if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout + LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT", + "the player has not logged in yet and not recently logout"); + else + { + // not expected _player or must checked in packet hanlder + sScriptMgr->OnPacketReceive(m_Socket, *packet); + (this->*opHandle->Handler)(*packet); + LogUnprocessedTail(packet); + } + break; + case STATUS_TRANSFER: + if (!_player) + LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet"); + else if (_player->IsInWorld()) + LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world"); + else + { sScriptMgr->OnPacketReceive(m_Socket, *packet); - (this->*opHandle.handler)(*packet); + (this->*opHandle->Handler)(*packet); LogUnprocessedTail(packet); + } + break; + case STATUS_AUTHED: + // prevent cheating with skip queue wait + if (m_inQueue) + { + LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet"); break; - case STATUS_NEVER: + } + + // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes + // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process. + if (packet->GetOpcode() == CMSG_CHAR_ENUM) + m_playerRecentlyLogout = false; + + sScriptMgr->OnPacketReceive(m_Socket, *packet); + (this->*opHandle->Handler)(*packet); + LogUnprocessedTail(packet); + break; + case STATUS_NEVER: TC_LOG_ERROR("network.opcode", "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() , GetPlayerInfo().c_str()); - break; - case STATUS_UNHANDLED: - TC_LOG_DEBUG("network.opcode", "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() + break; + case STATUS_UNHANDLED: + TC_LOG_ERROR("network.opcode", "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() , GetPlayerInfo().c_str()); - break; - } - } - catch (ByteBufferException const&) - { - TC_LOG_ERROR("misc", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", - packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); - packet->hexlike(); + break; } } + catch (ByteBufferException const&) + { + TC_LOG_ERROR("network", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", + packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); + packet->hexlike(); + } if (deletePacket) delete packet; @@ -593,8 +624,11 @@ void WorldSession::SendNotification(const char *format, ...) vsnprintf(szStr, 1024, format, ap); va_end(ap); - WorldPacket data(SMSG_NOTIFICATION, (strlen(szStr) + 1)); - data << szStr; + size_t len = strlen(szStr); + WorldPacket data(SMSG_NOTIFICATION, 2 + len); + data.WriteBits(len, 13); + data.FlushBits(); + data.append(szStr, len); SendPacket(&data); } } @@ -611,8 +645,11 @@ void WorldSession::SendNotification(uint32 string_id, ...) vsnprintf(szStr, 1024, format, ap); va_end(ap); - WorldPacket data(SMSG_NOTIFICATION, (strlen(szStr) + 1)); - data << szStr; + size_t len = strlen(szStr); + WorldPacket data(SMSG_NOTIFICATION, 2 + len); + data.WriteBits(len, 13); + data.FlushBits(); + data.append(szStr, len); SendPacket(&data); } } @@ -651,15 +688,21 @@ void WorldSession::SendAuthWaitQue(uint32 position) if (position == 0) { WorldPacket packet(SMSG_AUTH_RESPONSE, 1); + packet.WriteBit(0); // has queue info + packet.WriteBit(0); // has account info + packet.FlushBits(); packet << uint8(AUTH_OK); SendPacket(&packet); } else { WorldPacket packet(SMSG_AUTH_RESPONSE, 6); + packet.WriteBit(1); // has queue info + packet.WriteBit(0); // unk queue bool + packet.WriteBit(0); // has account info + packet.FlushBits(); packet << uint8(AUTH_WAIT_QUEUE); packet << uint32(position); - packet << uint8(0); // unk SendPacket(&packet); } } @@ -785,159 +828,6 @@ void WorldSession::SaveTutorialsData(SQLTransaction &trans) m_TutorialsChanged = false; } -void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi) -{ - data >> mi->flags; - data >> mi->flags2; - data >> mi->time; - data >> mi->pos.PositionXYZOStream(); - - if (mi->HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) - { - data.readPackGUID(mi->transport.guid); - - data >> mi->transport.pos.PositionXYZOStream(); - data >> mi->transport.time; - data >> mi->transport.seat; - - if (mi->HasExtraMovementFlag(MOVEMENTFLAG2_INTERPOLATED_MOVEMENT)) - data >> mi->transport.time2; - } - - if (mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (mi->HasExtraMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING))) - data >> mi->pitch; - - data >> mi->fallTime; - - if (mi->HasMovementFlag(MOVEMENTFLAG_FALLING)) - { - data >> mi->jump.zspeed; - data >> mi->jump.sinAngle; - data >> mi->jump.cosAngle; - data >> mi->jump.xyspeed; - } - - if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION)) - data >> mi->splineElevation; - - //! Anti-cheat checks. Please keep them in seperate if () blocks to maintain a clear overview. - //! Might be subject to latency, so just remove improper flags. - #ifdef TRINITY_DEBUG - #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \ - { \ - if (check) \ - { \ - TC_LOG_DEBUG("entities.unit", "WorldSession::ReadMovementInfo: Violation of MovementFlags found (%s). " \ - "MovementFlags: %u, MovementFlags2: %u for player GUID: %u. Mask %u will be removed.", \ - STRINGIZE(check), mi->GetMovementFlags(), mi->GetExtraMovementFlags(), GetPlayer()->GetGUIDLow(), maskToRemove); \ - mi->RemoveMovementFlag((maskToRemove)); \ - } \ - } - #else - #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \ - if (check) \ - mi->RemoveMovementFlag((maskToRemove)); - #endif - - - /*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid - in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD. - It will freeze clients that receive this player's movement info. - */ - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT), - MOVEMENTFLAG_ROOT); - - //! Cannot hover without SPELL_AURA_HOVER - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !GetPlayer()->HasAuraType(SPELL_AURA_HOVER), - MOVEMENTFLAG_HOVER); - - //! Cannot ascend and descend at the same time - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ASCENDING) && mi->HasMovementFlag(MOVEMENTFLAG_DESCENDING), - MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING); - - //! Cannot move left and right at the same time - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_RIGHT), - MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT); - - //! Cannot strafe left and right at the same time - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_RIGHT), - MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT); - - //! Cannot pitch up and down at the same time - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_PITCH_UP) && mi->HasMovementFlag(MOVEMENTFLAG_PITCH_DOWN), - MOVEMENTFLAG_PITCH_UP | MOVEMENTFLAG_PITCH_DOWN); - - //! Cannot move forwards and backwards at the same time - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FORWARD) && mi->HasMovementFlag(MOVEMENTFLAG_BACKWARD), - MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD); - - //! Cannot walk on water without SPELL_AURA_WATER_WALK - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_WATERWALKING) && !GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK), - MOVEMENTFLAG_WATERWALKING); - - //! Cannot feather fall without SPELL_AURA_FEATHER_FALL - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FALLING_SLOW) && !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL), - MOVEMENTFLAG_FALLING_SLOW); - - /*! Cannot fly if no fly auras present. Exception is being a GM. - Note that we check for account level instead of Player::IsGameMaster() because in some - situations it may be feasable to use .gm fly on as a GM without having .gm on, - e.g. aerial combat. - */ - - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSecurity() == SEC_PLAYER && - !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_FLY) && - !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED), - MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY); - - //! Cannot fly and fall at the same time - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY) && mi->HasMovementFlag(MOVEMENTFLAG_FALLING), - MOVEMENTFLAG_FALLING); - - REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ENABLED) && - (!GetPlayer()->movespline->Initialized() || GetPlayer()->movespline->Finalized()), MOVEMENTFLAG_SPLINE_ENABLED); - - #undef REMOVE_VIOLATING_FLAGS -} - -void WorldSession::WriteMovementInfo(WorldPacket* data, MovementInfo* mi) -{ - data->appendPackGUID(mi->guid); - - *data << mi->flags; - *data << mi->flags2; - *data << mi->time; - *data << mi->pos.PositionXYZOStream(); - - if (mi->HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) - { - data->appendPackGUID(mi->transport.guid); - - *data << mi->transport.pos.PositionXYZOStream(); - *data << mi->transport.time; - *data << mi->transport.seat; - - if (mi->HasExtraMovementFlag(MOVEMENTFLAG2_INTERPOLATED_MOVEMENT)) - *data << mi->transport.time2; - } - - if (mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || mi->HasExtraMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING)) - *data << mi->pitch; - - *data << mi->fallTime; - - if (mi->HasMovementFlag(MOVEMENTFLAG_FALLING)) - { - *data << mi->jump.zspeed; - *data << mi->jump.sinAngle; - *data << mi->jump.cosAngle; - *data << mi->jump.xyspeed; - } - - if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION)) - *data << mi->splineElevation; -} - void WorldSession::ReadAddonsInfo(WorldPacket &data) { if (data.rpos() + 4 > data.size()) @@ -1078,6 +968,57 @@ void WorldSession::SendAddonsInfo() SendPacket(&data); } +bool WorldSession::IsAddonRegistered(const std::string& prefix) const +{ + if (!_filterAddonMessages) // if we have hit the softcap (64) nothing should be filtered + return true; + + if (_registeredAddonPrefixes.empty()) + return false; + + std::vector<std::string>::const_iterator itr = std::find(_registeredAddonPrefixes.begin(), _registeredAddonPrefixes.end(), prefix); + return itr != _registeredAddonPrefixes.end(); +} + +void WorldSession::HandleUnregisterAddonPrefixesOpcode(WorldPacket& /*recvPacket*/) // empty packet +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_UNREGISTER_ALL_ADDON_PREFIXES"); + + _registeredAddonPrefixes.clear(); +} + +void WorldSession::HandleAddonRegisteredPrefixesOpcode(WorldPacket& recvPacket) +{ + TC_LOG_DEBUG("network", "WORLD: Received CMSG_ADDON_REGISTERED_PREFIXES"); + + // This is always sent after CMSG_UNREGISTER_ALL_ADDON_PREFIXES + + uint32 count = recvPacket.ReadBits(25); + + if (count > REGISTERED_ADDON_PREFIX_SOFTCAP) + { + // if we have hit the softcap (64) nothing should be filtered + _filterAddonMessages = false; + recvPacket.rfinish(); + return; + } + + std::vector<uint8> lengths(count); + for (uint32 i = 0; i < count; ++i) + lengths[i] = recvPacket.ReadBits(5); + + for (uint32 i = 0; i < count; ++i) + _registeredAddonPrefixes.push_back(recvPacket.ReadString(lengths[i])); + + if (_registeredAddonPrefixes.size() > REGISTERED_ADDON_PREFIX_SOFTCAP) // shouldn't happen + { + _filterAddonMessages = false; + return; + } + + _filterAddonMessages = true; +} + void WorldSession::SetPlayer(Player* player) { _player = player; @@ -1253,7 +1194,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)", Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(), - opcodeTable[p.GetOpcode()].name, p.GetOpcode(), packetCounter.amountCounter); + opcodeTable[p.GetOpcode()]->Name, p.GetOpcode(), packetCounter.amountCounter); switch (_policy) { @@ -1306,7 +1247,6 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co case CMSG_PLAYER_LOGOUT: // 0 1 case CMSG_LOGOUT_REQUEST: // 0 1 case CMSG_PET_RENAME: // 0 1 - case CMSG_QUESTGIVER_CANCEL: // 0 1 case CMSG_QUESTGIVER_REQUEST_REWARD: // 0 1 case CMSG_COMPLETE_CINEMATIC: // 0 1 case CMSG_BANKER_ACTIVATE: // 0 1 @@ -1316,8 +1256,6 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co case CMSG_DUEL_CANCELLED: // 0 1 case CMSG_CALENDAR_COMPLAIN: // 0 1 case CMSG_QUEST_QUERY: // 0 1.5 - case CMSG_ITEM_QUERY_SINGLE: // 0 1.5 - case CMSG_ITEM_NAME_QUERY: // 0 1.5 case CMSG_GAMEOBJECT_QUERY: // 0 1.5 case CMSG_CREATURE_QUERY: // 0 1.5 case CMSG_QUESTGIVER_STATUS_QUERY: // 0 1.5 @@ -1327,7 +1265,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co case CMSG_TAXIQUERYAVAILABLENODES: // 0 1.5 case CMSG_QUESTGIVER_QUERY_QUEST: // 0 1.5 case CMSG_PAGE_TEXT_QUERY: // 0 1.5 - case MSG_QUERY_GUILD_BANK_TEXT: // 0 1.5 + case CMSG_GUILD_BANK_QUERY_TEXT: // 0 1.5 case MSG_CORPSE_QUERY: // 0 1.5 case MSG_MOVE_SET_FACING: // 0 1.5 case CMSG_REQUEST_PARTY_MEMBER_STATS: // 0 1.5 @@ -1342,28 +1280,44 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co case CMSG_SELF_RES: // 0 1.5 case CMSG_UNLEARN_SKILL: // 0 1.5 case CMSG_EQUIPMENT_SET_SAVE: // 0 1.5 - case CMSG_DELETEEQUIPMENT_SET: // 0 1.5 + case CMSG_EQUIPMENT_SET_DELETE: // 0 1.5 case CMSG_DISMISS_CRITTER: // 0 1.5 case CMSG_REPOP_REQUEST: // 0 1.5 case CMSG_GROUP_INVITE: // 0 1.5 - case CMSG_GROUP_DECLINE: // 0 1.5 - case CMSG_GROUP_ACCEPT: // 0 1.5 + case CMSG_GROUP_INVITE_RESPONSE: // 0 1.5 case CMSG_GROUP_UNINVITE_GUID: // 0 1.5 - case CMSG_GROUP_UNINVITE: // 0 1.5 case CMSG_GROUP_DISBAND: // 0 1.5 case CMSG_BATTLEMASTER_JOIN_ARENA: // 0 1.5 - case CMSG_LEAVE_BATTLEFIELD: // 0 1.5 - case MSG_GUILD_BANK_LOG_QUERY: // 0 2 + case CMSG_BATTLEFIELD_LEAVE: // 0 1.5 + case CMSG_GUILD_BANK_LOG_QUERY: // 0 2 case CMSG_LOGOUT_CANCEL: // 0 2 case CMSG_REALM_SPLIT: // 0 2 case CMSG_ALTER_APPEARANCE: // 0 2 case CMSG_QUEST_CONFIRM_ACCEPT: // 0 2 - case MSG_GUILD_EVENT_LOG_QUERY: // 0 2.5 + case CMSG_GUILD_EVENT_LOG_QUERY: // 0 2.5 case CMSG_READY_FOR_ACCOUNT_DATA_TIMES: // 0 2.5 case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY: // 0 2.5 case CMSG_BEGIN_TRADE: // 0 2.5 case CMSG_INITIATE_TRADE: // 0 3 - case CMSG_MESSAGECHAT: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_GUILD: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_OFFICER: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_PARTY: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_RAID: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_WHISPER: // 0 3.5 + case CMSG_MESSAGECHAT_AFK: // 0 3.5 + case CMSG_MESSAGECHAT_BATTLEGROUND: // 0 3.5 + case CMSG_MESSAGECHAT_CHANNEL: // 0 3.5 + case CMSG_MESSAGECHAT_DND: // 0 3.5 + case CMSG_MESSAGECHAT_EMOTE: // 0 3.5 + case CMSG_MESSAGECHAT_GUILD: // 0 3.5 + case CMSG_MESSAGECHAT_OFFICER: // 0 3.5 + case CMSG_MESSAGECHAT_PARTY: // 0 3.5 + case CMSG_MESSAGECHAT_RAID: // 0 3.5 + case CMSG_MESSAGECHAT_RAID_WARNING: // 0 3.5 + case CMSG_MESSAGECHAT_SAY: // 0 3.5 + case CMSG_MESSAGECHAT_WHISPER: // 0 3.5 + case CMSG_MESSAGECHAT_YELL: // 0 3.5 case CMSG_INSPECT: // 0 3.5 case CMSG_AREA_SPIRIT_HEALER_QUERY: // not profiled { @@ -1389,8 +1343,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co break; } - case CMSG_GUILD_SET_PUBLIC_NOTE: // 1 2 1 async db query - case CMSG_GUILD_SET_OFFICER_NOTE: // 1 2 1 async db query + case CMSG_GUILD_SET_NOTE: // 1 2 1 async db query case CMSG_SET_CONTACT_NOTES: // 1 2.5 1 async db query case CMSG_CALENDAR_GET_CALENDAR: // 0 1.5 medium upload bandwidth usage case CMSG_GUILD_BANK_QUERY_TAB: // 0 3.5 medium upload bandwidth usage @@ -1410,7 +1363,6 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co case CMSG_SPELLCLICK: // not profiled case CMSG_GAMEOBJ_USE: // not profiled case CMSG_GAMEOBJ_REPORT_USE: // not profiled - case CMSG_REMOVE_GLYPH: // not profiled { maxPacketCounterAllowed = 20; break; @@ -1440,7 +1392,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: // not profiled case CMSG_DISMISS_CONTROLLED_VEHICLE: // not profiled case CMSG_REQUEST_VEHICLE_EXIT: // not profiled - case CMSG_CONTROLLER_EJECT_PASSENGER: // not profiled + case CMSG_EJECT_PASSENGER: // not profiled case CMSG_ITEM_REFUND: // not profiled case CMSG_SOCKET_GEMS: // not profiled case CMSG_WRAP_ITEM: // not profiled @@ -1477,9 +1429,9 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co case CMSG_GUILD_DECLINE: // not profiled case CMSG_GUILD_LEAVE: // not profiled case CMSG_GUILD_DISBAND: // not profiled - case CMSG_GUILD_LEADER: // not profiled + case CMSG_GUILD_SET_GUILD_MASTER: // not profiled case CMSG_GUILD_MOTD: // not profiled - case CMSG_GUILD_RANK: // not profiled + case CMSG_GUILD_SET_RANK_PERMISSIONS: // not profiled case CMSG_GUILD_ADD_RANK: // not profiled case CMSG_GUILD_DEL_RANK: // not profiled case CMSG_GUILD_INFO_TEXT: // not profiled diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index d5b2146ae79..bd159475c37 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -31,6 +31,7 @@ #include "Opcodes.h" #include "WorldPacket.h" #include "Cryptography/BigNumber.h" +#include "Opcodes.h" #include "AccountMgr.h" #include <unordered_set> @@ -86,6 +87,8 @@ enum AccountDataType #define GLOBAL_CACHE_MASK 0x15 #define PER_CHARACTER_CACHE_MASK 0xEA +#define REGISTERED_ADDON_PREFIX_SOFTCAP 64 + struct AccountData { AccountData() : Time(0), Data("") { } @@ -121,12 +124,15 @@ enum ChatRestrictionType enum CharterTypes { - GUILD_CHARTER_TYPE = 9, + GUILD_CHARTER_TYPE = 4, ARENA_TEAM_CHARTER_2v2_TYPE = 2, ARENA_TEAM_CHARTER_3v3_TYPE = 3, - ARENA_TEAM_CHARTER_5v5_TYPE = 5 + ARENA_TEAM_CHARTER_5v5_TYPE = 5, }; +#define DB2_REPLY_SPARSE 2442913102 +#define DB2_REPLY_ITEM 1344507586 + //class to deal with packet processing //allows to determine if next packet is safe to be processed class PacketFilter @@ -137,6 +143,7 @@ public: virtual bool Process(WorldPacket* /*packet*/) { return true; } virtual bool ProcessLogout() const { return true; } + static Opcodes DropHighBytes(Opcodes opcode) { return Opcodes(opcode & 0xFFFF); } protected: WorldSession* const m_pSession; @@ -208,7 +215,7 @@ struct PacketCounter class WorldSession { public: - WorldSession(uint32 id, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); + WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); bool PlayerLoading() const { return m_playerLoading; } @@ -218,20 +225,18 @@ class WorldSession void ReadAddonsInfo(WorldPacket& data); void SendAddonsInfo(); + bool IsAddonRegistered(const std::string& prefix) const; - void ReadMovementInfo(WorldPacket& data, MovementInfo* mi); - void WriteMovementInfo(WorldPacket* data, MovementInfo* mi); - - void SendPacket(WorldPacket* packet); + void SendPacket(WorldPacket* packet, bool forced = false); void SendNotification(const char *format, ...) ATTR_PRINTF(2, 3); void SendNotification(uint32 string_id, ...); void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName *declinedName); void SendPartyResult(PartyOperation operation, std::string const& member, PartyResult res, uint32 val = 0); void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2, 3); - void SendSetPhaseShift(uint32 phaseShift); + void SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps, std::set<uint32> const& worldMapAreaSwaps); void SendQueryTimeResponse(); - void SendAuthResponse(uint8 code, bool shortForm, uint32 queuePos = 0); + void SendAuthResponse(uint8 code, bool queued, uint32 queuePos = 0); void SendClientCacheVersion(uint32 version); rbac::RBACData* GetRBACData(); @@ -241,6 +246,7 @@ class WorldSession AccountTypes GetSecurity() const { return _security; } uint32 GetAccountId() const { return _accountId; } + uint32 GetBattlenetAccountId() const { return _battlenetAccountId; } Player* GetPlayer() const { return _player; } std::string const& GetPlayerName() const; std::string GetPlayerInfo() const; @@ -283,12 +289,12 @@ class WorldSession //void SendTestCreatureQueryOpcode(uint32 entry, uint64 guid, uint32 testvalue); void SendNameQueryOpcode(uint64 guid); + bool CanOpenMailBox(uint64 guid); + void SendTrainerList(uint64 guid); void SendTrainerList(uint64 guid, std::string const& strTitle); void SendListInventory(uint64 guid); void SendShowBank(uint64 guid); - bool CanOpenMailBox(uint64 guid); - void SendShowMailBox(uint64 guid); void SendTabardVendorActivate(uint64 guid); void SendSpiritResurrect(); void SendBindPoint(Creature* npc); @@ -297,7 +303,7 @@ class WorldSession void SendBattleGroundList(uint64 guid, BattlegroundTypeId bgTypeId = BATTLEGROUND_RB); - void SendTradeStatus(TradeStatus status); + void SendTradeStatus(TradeStatus status, int8 clearSlot = 0); void SendUpdateTrade(bool trader_data = true); void SendCancelTrade(); @@ -336,9 +342,10 @@ class WorldSession bool SendItemInfo(uint32 itemid, WorldPacket data); //auction void SendAuctionHello(uint64 guid, Creature* unit); - void SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError = 0); + void SendAuctionCommandResult(AuctionEntry* auction, uint32 Action, uint32 ErrorCode, uint32 bidError = 0); void SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template); void SendAuctionOwnerNotification(AuctionEntry* auction); + void SendAuctionRemovedNotification(uint32 auctionId, uint32 itemEntry, int32 randomPropertyId); //Item Enchantment void SendEnchantmentLog(uint64 target, uint64 caster, uint32 itemId, uint32 enchantId); @@ -381,19 +388,15 @@ class WorldSession else m_timeOutTime -= diff; } - void ResetTimeOutTime() - { - m_timeOutTime = sWorld->getIntConfig(CONFIG_SOCKET_TIMEOUTTIME); - } - bool IsConnectionIdle() const - { - return (m_timeOutTime <= 0 && !m_inQueue); - } + void ResetTimeOutTime() { m_timeOutTime = sWorld->getIntConfig(CONFIG_SOCKET_TIMEOUTTIME); } + bool IsConnectionIdle() const { return (m_timeOutTime <= 0 && !m_inQueue); } // Recruit-A-Friend Handling uint32 GetRecruiterId() const { return recruiterId; } bool IsARecruiter() const { return isRecruiter; } + z_stream_s* GetCompressionStream() { return _compressionStream; } + public: // opcodes handlers void Handle_NULL(WorldPacket& recvPacket); // not used @@ -406,9 +409,13 @@ class WorldSession void HandleCharCreateOpcode(WorldPacket& recvPacket); void HandleCharCreateCallback(PreparedQueryResult result, CharacterCreateInfo* createInfo); void HandlePlayerLoginOpcode(WorldPacket& recvPacket); + void HandleLoadScreenOpcode(WorldPacket& recvPacket); void HandleCharEnum(PreparedQueryResult result); void HandlePlayerLogin(LoginQueryHolder * holder); void HandleCharFactionOrRaceChange(WorldPacket& recvData); + void HandleRandomizeCharNameOpcode(WorldPacket& recvData); + void HandleReorderCharacters(WorldPacket& recvData); + void HandleOpeningCinematic(WorldPacket& recvData); // played time void HandlePlayedTime(WorldPacket& recvPacket); @@ -417,6 +424,7 @@ class WorldSession void HandleMoveUnRootAck(WorldPacket& recvPacket); void HandleMoveRootAck(WorldPacket& recvPacket); void HandleLookingForGroup(WorldPacket& recvPacket); + void HandleReturnToGraveyard(WorldPacket& recvPacket); // new inspect void HandleInspectOpcode(WorldPacket& recvPacket); @@ -443,6 +451,7 @@ class WorldSession void HandleMoveTeleportAck(WorldPacket& recvPacket); void HandleForceSpeedChangeAck(WorldPacket& recvData); + void HandleSetCollisionHeightAck(WorldPacket& recvPacket); void HandlePingOpcode(WorldPacket& recvPacket); void HandleRepopRequestOpcode(WorldPacket& recvPacket); @@ -481,8 +490,6 @@ class WorldSession void HandleDelIgnoreOpcode(WorldPacket& recvPacket); void HandleSetContactNotesOpcode(WorldPacket& recvPacket); void HandleBugOpcode(WorldPacket& recvPacket); - void HandleSetAmmoOpcode(WorldPacket& recvPacket); - void HandleItemNameQueryOpcode(WorldPacket& recvPacket); void HandleAreaTriggerOpcode(WorldPacket& recvPacket); @@ -525,11 +532,11 @@ class WorldSession void HandleGroupInviteOpcode(WorldPacket& recvPacket); //void HandleGroupCancelOpcode(WorldPacket& recvPacket); - void HandleGroupAcceptOpcode(WorldPacket& recvPacket); - void HandleGroupDeclineOpcode(WorldPacket& recvPacket); + void HandleGroupInviteResponseOpcode(WorldPacket& recvPacket); void HandleGroupUninviteOpcode(WorldPacket& recvPacket); void HandleGroupUninviteGuidOpcode(WorldPacket& recvPacket); void HandleGroupSetLeaderOpcode(WorldPacket& recvPacket); + void HandleGroupSetRolesOpcode(WorldPacket& recvData); void HandleGroupDisbandOpcode(WorldPacket& recvPacket); void HandleOptOutOfLootOpcode(WorldPacket& recvData); void HandleLootMethodOpcode(WorldPacket& recvPacket); @@ -540,6 +547,7 @@ class WorldSession void HandleRaidReadyCheckFinishedOpcode(WorldPacket& recvData); void HandleGroupRaidConvertOpcode(WorldPacket& recvData); void HandleGroupChangeSubGroupOpcode(WorldPacket& recvData); + void HandleGroupSwapSubGroupOpcode(WorldPacket& recvData); void HandleGroupAssistantLeaderOpcode(WorldPacket& recvData); void HandlePartyAssignmentOpcode(WorldPacket& recvData); @@ -553,27 +561,41 @@ class WorldSession void HandleTurnInPetitionOpcode(WorldPacket& recvData); void HandleGuildQueryOpcode(WorldPacket& recvPacket); - void HandleGuildCreateOpcode(WorldPacket& recvPacket); void HandleGuildInviteOpcode(WorldPacket& recvPacket); void HandleGuildRemoveOpcode(WorldPacket& recvPacket); void HandleGuildAcceptOpcode(WorldPacket& recvPacket); void HandleGuildDeclineOpcode(WorldPacket& recvPacket); - void HandleGuildInfoOpcode(WorldPacket& recvPacket); void HandleGuildEventLogQueryOpcode(WorldPacket& recvPacket); void HandleGuildRosterOpcode(WorldPacket& recvPacket); + void HandleGuildRewardsQueryOpcode(WorldPacket& recvPacket); void HandleGuildPromoteOpcode(WorldPacket& recvPacket); void HandleGuildDemoteOpcode(WorldPacket& recvPacket); + void HandleGuildAssignRankOpcode(WorldPacket& recvPacket); void HandleGuildLeaveOpcode(WorldPacket& recvPacket); void HandleGuildDisbandOpcode(WorldPacket& recvPacket); - void HandleGuildLeaderOpcode(WorldPacket& recvPacket); + void HandleGuildSetGuildMaster(WorldPacket& recvPacket); void HandleGuildMOTDOpcode(WorldPacket& recvPacket); - void HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket); - void HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket); - void HandleGuildRankOpcode(WorldPacket& recvPacket); + void HandleGuildNewsUpdateStickyOpcode(WorldPacket& recvPacket); + void HandleGuildSetNoteOpcode(WorldPacket& recvPacket); + void HandleGuildQueryRanksOpcode(WorldPacket& recvPacket); + void HandleGuildQueryNewsOpcode(WorldPacket& recvPacket); + void HandleGuildSetRankPermissionsOpcode(WorldPacket& recvPacket); void HandleGuildAddRankOpcode(WorldPacket& recvPacket); void HandleGuildDelRankOpcode(WorldPacket& recvPacket); void HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket); void HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket); + void HandleGuildRequestPartyState(WorldPacket& recvPacket); + void HandleGuildRequestMaxDailyXP(WorldPacket& recvPacket); + void HandleAutoDeclineGuildInvites(WorldPacket& recvPacket); + + void HandleGuildFinderAddRecruit(WorldPacket& recvPacket); + void HandleGuildFinderBrowse(WorldPacket& recvPacket); + void HandleGuildFinderDeclineRecruit(WorldPacket& recvPacket); + void HandleGuildFinderGetApplications(WorldPacket& recvPacket); + void HandleGuildFinderGetRecruits(WorldPacket& recvPacket); + void HandleGuildFinderPostRequest(WorldPacket& recvPacket); + void HandleGuildFinderRemoveRecruit(WorldPacket& recvPacket); + void HandleGuildFinderSetGuildPost(WorldPacket& recvPacket); void HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvPacket); void HandleTaxiQueryAvailableNodes(WorldPacket& recvPacket); @@ -602,6 +624,7 @@ class WorldSession void HandleStableRevivePet(WorldPacket& recvPacket); void HandleStableSwapPet(WorldPacket& recvPacket); void HandleStableSwapPetCallback(PreparedQueryResult result, uint32 petId); + void SendTrainerBuyFailed(uint64 guid, uint32 spellId, uint32 reason); void HandleDuelAcceptedOpcode(WorldPacket& recvPacket); void HandleDuelCancelledOpcode(WorldPacket& recvPacket); @@ -637,13 +660,13 @@ class WorldSession void HandleMailCreateTextItem(WorldPacket& recvData); void HandleQueryNextMailTime(WorldPacket& recvData); void HandleCancelChanneling(WorldPacket& recvData); + void SendShowMailBox(uint64 guid); void SendItemPageInfo(ItemTemplate* itemProto); void HandleSplitItemOpcode(WorldPacket& recvPacket); void HandleSwapInvItemOpcode(WorldPacket& recvPacket); void HandleDestroyItemOpcode(WorldPacket& recvPacket); void HandleAutoEquipItemOpcode(WorldPacket& recvPacket); - void HandleItemQuerySingleOpcode(WorldPacket& recvPacket); void HandleSellItemOpcode(WorldPacket& recvPacket); void HandleBuyItemInSlotOpcode(WorldPacket& recvPacket); void HandleBuyItemOpcode(WorldPacket& recvPacket); @@ -692,6 +715,7 @@ class WorldSession void HandleQuestPushResult(WorldPacket& recvPacket); void HandleMessagechatOpcode(WorldPacket& recvPacket); + void HandleAddonMessagechatOpcode(WorldPacket& recvPacket); void SendPlayerNotFoundNotice(std::string const& name); void SendPlayerAmbiguousNotice(std::string const& name); void SendWrongFactionNotice(); @@ -699,6 +723,9 @@ class WorldSession void HandleTextEmoteOpcode(WorldPacket& recvPacket); void HandleChatIgnoredOpcode(WorldPacket& recvPacket); + void HandleUnregisterAddonPrefixesOpcode(WorldPacket& recvPacket); + void HandleAddonRegisteredPrefixesOpcode(WorldPacket& recvPacket); + void HandleReclaimCorpseOpcode(WorldPacket& recvPacket); void HandleCorpseQueryOpcode(WorldPacket& recvPacket); void HandleCorpseMapPositionQuery(WorldPacket& recvPacket); @@ -738,7 +765,7 @@ class WorldSession //Pet void HandlePetAction(WorldPacket& recvData); void HandlePetStopAttack(WorldPacket& recvData); - void HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid, uint16 flag, uint64 guid2); + void HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid, uint16 flag, uint64 guid2, float x, float y, float z); void HandlePetNameQuery(WorldPacket& recvData); void HandlePetSetAction(WorldPacket& recvData); void HandlePetAbandon(WorldPacket& recvData); @@ -768,13 +795,17 @@ class WorldSession void HandleBattlefieldLeaveOpcode(WorldPacket& recvData); void HandleBattlemasterJoinArena(WorldPacket& recvData); void HandleReportPvPAFK(WorldPacket& recvData); + void HandleRequestRatedBgInfo(WorldPacket& recvData); + void HandleRequestPvpOptions(WorldPacket& recvData); + void HandleRequestPvpReward(WorldPacket& recvData); + void HandleRequestRatedBgStats(WorldPacket& recvData); // Battlefield - void SendBfInvitePlayerToWar(uint32 battleId, uint32 zoneId, uint32 time); - void SendBfInvitePlayerToQueue(uint32 battleId); - void SendBfQueueInviteResponse(uint32 battleId, uint32 zoneId, bool canQueue = true, bool full = false); - void SendBfEntered(uint32 battleId); - void SendBfLeaveMessage(uint32 battleId, BFLeaveReason reason = BF_LEAVE_REASON_EXITED); + void SendBfInvitePlayerToWar(uint64 guid, uint32 zoneId, uint32 time); + void SendBfInvitePlayerToQueue(uint64 guid); + void SendBfQueueInviteResponse(uint64 guid, uint32 zoneId, bool canQueue = true, bool full = false); + void SendBfEntered(uint64 guid); + void SendBfLeaveMessage(uint64 guid, BFLeaveReason reason = BF_LEAVE_REASON_EXITED); void HandleBfQueueInviteResponse(WorldPacket& recvData); void HandleBfEntryInviteResponse(WorldPacket& recvData); void HandleBfExitRequest(WorldPacket& recvData); @@ -797,8 +828,9 @@ class WorldSession // Looking for Dungeon/Raid void HandleLfgSetCommentOpcode(WorldPacket& recvData); - void HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& recvData); - void HandleLfgPartyLockInfoRequestOpcode(WorldPacket& recvData); + void HandleLfgGetLockInfoOpcode(WorldPacket& recvData); + void SendLfgPlayerLockInfo(); + void SendLfgPartyLockInfo(); void HandleLfgJoinOpcode(WorldPacket& recvData); void HandleLfgLeaveOpcode(WorldPacket& recvData); void HandleLfgSetRolesOpcode(WorldPacket& recvData); @@ -809,8 +841,7 @@ class WorldSession void HandleLfrLeaveOpcode(WorldPacket& recvData); void HandleLfgGetStatus(WorldPacket& recvData); - void SendLfgUpdatePlayer(lfg::LfgUpdateData const& updateData); - void SendLfgUpdateParty(lfg::LfgUpdateData const& updateData); + void SendLfgUpdateStatus(lfg::LfgUpdateData const& updateData, bool party); void SendLfgRoleChosen(uint64 guid, uint8 roles); void SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& pRoleCheck); void SendLfgLfrList(bool update); @@ -827,6 +858,7 @@ class WorldSession void HandleInspectArenaTeamsOpcode(WorldPacket& recvData); void HandleArenaTeamQueryOpcode(WorldPacket& recvData); void HandleArenaTeamRosterOpcode(WorldPacket& recvData); + void HandleArenaTeamCreateOpcode(WorldPacket& recvData); void HandleArenaTeamInviteOpcode(WorldPacket& recvData); void HandleArenaTeamAcceptOpcode(WorldPacket& recvData); void HandleArenaTeamDeclineOpcode(WorldPacket& recvData); @@ -869,6 +901,7 @@ class WorldSession void HandleGuildBankBuyTab(WorldPacket& recvData); void HandleQueryGuildBankTabText(WorldPacket& recvData); void HandleSetGuildBankTabText(WorldPacket& recvData); + void HandleGuildQueryXPOpcode(WorldPacket& recvData); // Refer-a-Friend void HandleGrantLevel(WorldPacket& recvData); @@ -896,12 +929,28 @@ class WorldSession void SendCalendarRaidLockoutUpdated(InstanceSave const* save); void HandleSetSavedInstanceExtend(WorldPacket& recvData); + // Void Storage + void HandleVoidStorageUnlock(WorldPacket& recvData); + void HandleVoidStorageQuery(WorldPacket& recvData); + void HandleVoidStorageTransfer(WorldPacket& recvData); + void HandleVoidSwapItem(WorldPacket& recvData); + void SendVoidStorageTransferResult(VoidTransferError result); + + // Transmogrification + void HandleTransmogrifyItems(WorldPacket& recvData); + + // Reforge + void HandleReforgeItemOpcode(WorldPacket& recvData); + void SendReforgeResult(bool success); + + // Miscellaneous void HandleSpellClick(WorldPacket& recvData); void HandleMirrorImageDataRequest(WorldPacket& recvData); void HandleAlterAppearance(WorldPacket& recvData); void HandleRemoveGlyph(WorldPacket& recvData); void HandleCharCustomize(WorldPacket& recvData); void HandleQueryInspectAchievements(WorldPacket& recvData); + void HandleGuildAchievementProgressQuery(WorldPacket& recvData); void HandleEquipmentSetSave(WorldPacket& recvData); void HandleEquipmentSetDelete(WorldPacket& recvData); void HandleEquipmentSetUse(WorldPacket& recvData); @@ -912,7 +961,16 @@ class WorldSession void HandleEjectPassenger(WorldPacket& data); void HandleEnterPlayerVehicle(WorldPacket& data); void HandleUpdateProjectilePosition(WorldPacket& recvPacket); + void HandleRequestHotfix(WorldPacket& recvPacket); void HandleUpdateMissileTrajectory(WorldPacket& recvPacket); + void HandleViolenceLevel(WorldPacket& recvPacket); + void HandleObjectUpdateFailedOpcode(WorldPacket& recvPacket); + void HandleRequestCategoryCooldowns(WorldPacket& recvPacket); + int32 HandleEnableNagleAlgorithm(); + + // Compact Unit Frames (4.x) + void HandleSaveCUFProfiles(WorldPacket& recvPacket); + void SendLoadCUFProfiles(); private: void InitializeQueryCallbackParameters(); @@ -987,6 +1045,7 @@ class WorldSession AccountTypes _security; uint32 _accountId; + uint32 _battlenetAccountId; uint8 m_expansion; typedef std::list<AddonInfo> AddonsList; @@ -1008,9 +1067,12 @@ class WorldSession uint32 m_Tutorials[MAX_ACCOUNT_TUTORIAL_VALUES]; bool m_TutorialsChanged; AddonsList m_addonsList; + std::vector<std::string> _registeredAddonPrefixes; + bool _filterAddonMessages; uint32 recruiterId; bool isRecruiter; LockedQueue<WorldPacket*> _recvQueue; + z_stream_s* _compressionStream; rbac::RBACData* _RBACData; uint32 expireTime; bool forceExit; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index ea0bfc234bf..46a1bf8f16d 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -1,20 +1,20 @@ /* -* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> -* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at your -* option) any later version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License along -* with this program. If not, see <http://www.gnu.org/licenses/>. -*/ + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ #include <memory> #include "WorldSocket.h" @@ -23,6 +23,7 @@ #include "ScriptMgr.h" #include "SHA1.h" #include "PacketLog.h" +#include "BattlenetAccountMgr.h" using boost::asio::ip::tcp; @@ -34,15 +35,17 @@ WorldSocket::WorldSocket(tcp::socket&& socket) void WorldSocket::Start() { AsyncReadHeader(); - HandleSendAuthSession(); + + // not an opcode. this packet sends raw string WORLD OF WARCRAFT CONNECTION - SERVER TO CLIENT" + // because of our implementation of WorldPacket sending, bytes "WO" become the opcode + WorldPacket packet(MSG_VERIFY_CONNECTIVITY); + packet << "RLD OF WARCRAFT CONNECTION - SERVER TO CLIENT"; + AsyncWrite(packet); } void WorldSocket::HandleSendAuthSession() { WorldPacket packet(SMSG_AUTH_CHALLENGE, 37); - packet << uint32(1); // 1...31 - packet << uint32(_authSeed); - BigNumber seed1; seed1.SetRand(16 * 8); packet.append(seed1.AsByteArray(16).get(), 16); // new encryption seeds @@ -51,6 +54,8 @@ void WorldSocket::HandleSendAuthSession() seed2.SetRand(16 * 8); packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds + packet << uint32(_authSeed); + packet << uint8(1); AsyncWrite(packet); } @@ -78,7 +83,7 @@ void WorldSocket::ReadDataHandler(boost::system::error_code error, size_t transf { header->size -= sizeof(header->cmd); - uint16 opcode = uint16(header->cmd); + Opcodes opcode = PacketFilter::DropHighBytes(Opcodes(header->cmd)); std::string opcodeName = GetOpcodeNameForLogging(opcode); @@ -115,6 +120,36 @@ void WorldSocket::ReadDataHandler(boost::system::error_code error, size_t transf TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); sScriptMgr->OnPacketReceive(shared_from_this(), packet); break; + case CMSG_LOG_DISCONNECT: + packet.rfinish(); // contains uint32 disconnectReason; + TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + return; + // not an opcode, client sends string "WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER" without opcode + // first 4 bytes become the opcode (2 dropped) + case MSG_VERIFY_CONNECTIVITY: + { + TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + std::string str; + packet >> str; + if (str != "D OF WARCRAFT CONNECTION - CLIENT TO SERVER") + { + CloseSocket(); + break; + } + + HandleSendAuthSession(); + break; + } + case CMSG_ENABLE_NAGLE: + { + TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + if (_worldSession) + _worldSession->HandleEnableNagleAlgorithm(); + break; + } default: { if (!_worldSession) @@ -144,6 +179,9 @@ void WorldSocket::AsyncWrite(WorldPacket& packet) if (sPacketLog->CanLogPacket()) sPacketLog->LogPacket(packet, SERVER_TO_CLIENT); + if (_worldSession && packet.size() > 0x400) + packet.Compress(_worldSession->GetCompressionStream()); + TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(packet.GetOpcode()).c_str()); ServerPktHeader header(packet.size() + 2, packet.GetOpcode()); @@ -164,17 +202,57 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) uint8 digest[20]; uint32 clientSeed; uint8 security; + uint16 clientBuild; uint32 id; + uint32 addonSize; LocaleConstant locale; std::string account; SHA1Hash sha; - uint32 clientBuild; - uint32 unk2, unk3, unk5, unk6, unk7; - uint64 unk4; - WorldPacket packet, SendAddonPacked; BigNumber k; bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); + WorldPacket addonsData; + + recvPacket.read_skip<uint32>(); + recvPacket.read_skip<uint32>(); + recvPacket.read_skip<uint8>(); + recvPacket >> digest[10]; + recvPacket >> digest[18]; + recvPacket >> digest[12]; + recvPacket >> digest[5]; + recvPacket.read_skip<uint64>(); + recvPacket >> digest[15]; + recvPacket >> digest[9]; + recvPacket >> digest[19]; + recvPacket >> digest[4]; + recvPacket >> digest[7]; + recvPacket >> digest[16]; + recvPacket >> digest[3]; + recvPacket >> clientBuild; + recvPacket >> digest[8]; + recvPacket.read_skip<uint32>(); + recvPacket.read_skip<uint8>(); + recvPacket >> digest[17]; + recvPacket >> digest[6]; + recvPacket >> digest[0]; + recvPacket >> digest[1]; + recvPacket >> digest[11]; + recvPacket >> clientSeed; + recvPacket >> digest[2]; + recvPacket.read_skip<uint32>(); + recvPacket >> digest[14]; + recvPacket >> digest[13]; + + recvPacket >> addonSize; + if (addonSize) + { + addonsData.resize(addonSize); + recvPacket.read((uint8*)addonsData.contents(), addonSize); + } + + recvPacket.ReadBit(); + uint32 accountNameLength = recvPacket.ReadBits(12); + account = recvPacket.ReadString(accountNameLength); if (sWorld->IsClosed()) { SendAuthResponseError(AUTH_REJECT); @@ -182,29 +260,23 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) return; } - // Read the content of the packet - recvPacket >> clientBuild; - recvPacket >> unk2; - recvPacket >> account; - recvPacket >> unk3; - recvPacket >> clientSeed; - recvPacket >> unk5 >> unk6 >> unk7; - recvPacket >> unk4; - recvPacket.read(digest, 20); - - TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u", - clientBuild, - unk2, - account.c_str(), - unk3, - clientSeed); - // Get the account information from the realmd database // 0 1 2 3 4 5 6 7 8 // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); - - stmt->setString(0, account); + PreparedStatement* stmt; + uint32 battlenetAccountId = 0; + uint8 battlenetAccountIndex = 0; + if (Battlenet::AccountMgr::GetAccountIdAndIndex(account, &battlenetAccountId, &battlenetAccountIndex)) + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET); + stmt->setUInt32(0, battlenetAccountId); + stmt->setUInt8(1, battlenetAccountIndex); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); + stmt->setString(0, account); + } PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -367,13 +439,13 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); // NOTE ATM the socket is single-threaded, have this in mind ... - _worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); + _worldSession = new WorldSession(id, battlenetAccountId, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); _authCrypt.Init(&k); _worldSession->LoadGlobalAccountData(); _worldSession->LoadTutorialsData(); - _worldSession->ReadAddonsInfo(recvPacket); + _worldSession->ReadAddonsInfo(addonsData); _worldSession->LoadPermissions(); // At this point, we can safely hook a successful login @@ -389,6 +461,8 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) void WorldSocket::SendAuthResponseError(uint8 code) { WorldPacket packet(SMSG_AUTH_RESPONSE, 1); + packet.WriteBit(0); // has queue info + packet.WriteBit(0); // has account info packet << uint8(code); AsyncWrite(packet); @@ -400,8 +474,8 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket) uint32 latency; // Get the ping packet content - recvPacket >> ping; recvPacket >> latency; + recvPacket >> ping; if (_LastPingTime == steady_clock::time_point()) { diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 1fa08c2b5f1..4e1cbe743fd 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -30,7 +30,7 @@ namespace boost } #include "Common.h" -#include "AuthCrypt.h" +#include "WorldPacketCrypt.h" #include "ServerPktHeader.h" #include "Socket.h" #include "Util.h" @@ -119,7 +119,7 @@ private: void HandlePing(WorldPacket& recvPacket); uint32 _authSeed; - AuthCrypt _authCrypt; + WorldPacketCrypt _authCrypt; std::chrono::steady_clock::time_point _LastPingTime; uint32 _OverSpeedPings; diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index aa1f6a49413..628e4e0721d 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -200,7 +200,7 @@ enum AuraType SPELL_AURA_MOD_MELEE_HASTE = 138, SPELL_AURA_FORCE_REACTION = 139, SPELL_AURA_MOD_RANGED_HASTE = 140, - SPELL_AURA_MOD_RANGED_AMMO_HASTE = 141, + SPELL_AURA_141 = 141, // old SPELL_AURA_MOD_RANGED_AMMO_HASTE, unused now SPELL_AURA_MOD_BASE_RESISTANCE_PCT = 142, SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE = 143, SPELL_AURA_SAFE_FALL = 144, @@ -212,14 +212,14 @@ enum AuraType SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT = 150, SPELL_AURA_TRACK_STEALTHED = 151, // Track Stealthed SPELL_AURA_MOD_DETECTED_RANGE = 152, // Mod Detected Range - SPELL_AURA_SPLIT_DAMAGE_FLAT = 153, // Split Damage Flat + SPELL_AURA_153 = 153, // old SPELL_AURA_SPLIT_DAMAGE_FLAT. unused 4.3.4 SPELL_AURA_MOD_STEALTH_LEVEL = 154, // Stealth Level Modifier SPELL_AURA_MOD_WATER_BREATHING = 155, // Mod Water Breathing SPELL_AURA_MOD_REPUTATION_GAIN = 156, // Mod Reputation Gain SPELL_AURA_PET_DAMAGE_MULTI = 157, // Mod Pet Damage SPELL_AURA_MOD_SHIELD_BLOCKVALUE = 158, SPELL_AURA_NO_PVP_CREDIT = 159, - SPELL_AURA_MOD_AOE_AVOIDANCE = 160, + SPELL_AURA_160 = 160, // old SPELL_AURA_MOD_AOE_AVOIDANCE. Unused 4.3.4 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT = 161, SPELL_AURA_POWER_BURN = 162, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS = 163, @@ -228,7 +228,7 @@ enum AuraType SPELL_AURA_MOD_ATTACK_POWER_PCT = 166, SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT = 167, SPELL_AURA_MOD_DAMAGE_DONE_VERSUS = 168, - SPELL_AURA_MOD_CRIT_PERCENT_VERSUS = 169, + SPELL_AURA_169 = 169, // old SPELL_AURA_MOD_CRIT_PERCENT_VERSUS. unused 4.3.4 SPELL_AURA_DETECT_AMORE = 170, SPELL_AURA_MOD_SPEED_NOT_STACK = 171, SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK = 172, @@ -237,7 +237,7 @@ enum AuraType SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT = 175, SPELL_AURA_SPIRIT_OF_REDEMPTION = 176, SPELL_AURA_AOE_CHARM = 177, - SPELL_AURA_MOD_DEBUFF_RESISTANCE = 178, + SPELL_AURA_178 = 178, // old SPELL_AURA_MOD_DEBUFF_RESISTANCE, unused SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE = 179, SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS = 180, SPELL_AURA_181 = 181, // old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS - possible flat spell crit damage versus @@ -258,7 +258,7 @@ enum AuraType SPELL_AURA_MOD_COOLDOWN = 196, // only 24818 Noxious Breath SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE = 197, SPELL_AURA_198 = 198, // old SPELL_AURA_MOD_ALL_WEAPON_SKILLS - SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT = 199, + SPELL_AURA_199 = 199, // old SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT. unused 4.3.4 SPELL_AURA_MOD_XP_PCT = 200, SPELL_AURA_FLY = 201, SPELL_AURA_IGNORE_COMBAT_RESULT = 202, @@ -271,12 +271,12 @@ enum AuraType SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS = 209, SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS = 210, SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK = 211, - SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT = 212, + SPELL_AURA_212 = 212, // old SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT. unused 4.3.4 SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT = 213, SPELL_AURA_214 = 214, SPELL_AURA_ARENA_PREPARATION = 215, SPELL_AURA_HASTE_SPELLS = 216, - SPELL_AURA_MOD_MELEE_HASTE_2 = 217, // NYI + SPELL_AURA_MOD_MELEE_HASTE_2 = 217, SPELL_AURA_HASTE_RANGED = 218, SPELL_AURA_MOD_MANA_REGEN_FROM_STAT = 219, SPELL_AURA_MOD_RATING_FROM_STAT = 220, @@ -289,7 +289,7 @@ enum AuraType SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE = 227, SPELL_AURA_DETECT_STEALTH = 228, SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE = 229, - SPELL_AURA_230 = 230, + SPELL_AURA_MOD_MAX_HEALTH = 230, SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE = 231, SPELL_AURA_MECHANIC_DURATION_MOD = 232, SPELL_AURA_CHANGE_MODEL_FOR_ALL_HUMANOIDS = 233, // client-side only @@ -318,7 +318,7 @@ enum AuraType SPELL_AURA_NO_REAGENT_USE = 256, SPELL_AURA_MOD_TARGET_RESIST_BY_SPELL_CLASS = 257, SPELL_AURA_258 = 258, - SPELL_AURA_MOD_HOT_PCT = 259, + SPELL_AURA_259 = 259, // old SPELL_AURA_MOD_HOT_PCT, unused 4.3.4 SPELL_AURA_SCREEN_EFFECT = 260, SPELL_AURA_PHASE = 261, SPELL_AURA_ABILITY_IGNORE_AURASTATE = 262, @@ -327,19 +327,19 @@ enum AuraType SPELL_AURA_265 = 265, SPELL_AURA_266 = 266, SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL = 267, - SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT = 268, + SPELL_AURA_268 = 268, // old SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT. unused 4.3.4 SPELL_AURA_MOD_IGNORE_TARGET_RESIST = 269, - SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST = 270, // Possibly need swap vs 195 aura used only in 1 spell Chaos Bolt Passive + SPELL_AURA_270 = 270, // old SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, unused 4.3.4 SPELL_AURA_MOD_DAMAGE_FROM_CASTER = 271, SPELL_AURA_IGNORE_MELEE_RESET = 272, SPELL_AURA_X_RAY = 273, - SPELL_AURA_ABILITY_CONSUME_NO_AMMO = 274, + SPELL_AURA_274 = 274, // old SPELL_AURA_ABILITY_CONSUME_NO_AMMO, unused 4.3.4 SPELL_AURA_MOD_IGNORE_SHAPESHIFT = 275, - SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC = 276, // NYI - SPELL_AURA_MOD_MAX_AFFECTED_TARGETS = 277, + SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC = 276, + SPELL_AURA_277 = 277, // old SPELL_AURA_MOD_MAX_AFFECTED_TARGETS. unused 4.3.4 SPELL_AURA_MOD_DISARM_RANGED = 278, SPELL_AURA_INITIALIZE_IMAGES = 279, - SPELL_AURA_MOD_ARMOR_PENETRATION_PCT = 280, + SPELL_AURA_280 = 280, // old SPELL_AURA_MOD_ARMOR_PENETRATION_PCT unused 4.3.4 SPELL_AURA_MOD_HONOR_GAIN_PCT = 281, SPELL_AURA_MOD_BASE_HEALTH_PCT = 282, SPELL_AURA_MOD_HEALING_RECEIVED = 283, // Possibly only for some spell family class spells @@ -367,16 +367,70 @@ enum AuraType SPELL_AURA_MOD_MINIMUM_SPEED = 305, SPELL_AURA_306 = 306, SPELL_AURA_HEAL_ABSORB_TEST = 307, - SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER = 308, // NYI - SPELL_AURA_309 = 309, + SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER = 308, + SPELL_AURA_309 = 309, // Not used in 4.3.4 SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE = 310, SPELL_AURA_311 = 311, - SPELL_AURA_312 = 312, - SPELL_AURA_313 = 313, + SPELL_AURA_ANIM_REPLACEMENT_SET = 312, + SPELL_AURA_313 = 313, // Not used in 4.3.4 - related to mounts SPELL_AURA_PREVENT_RESURRECTION = 314, SPELL_AURA_UNDERWATER_WALKING = 315, - SPELL_AURA_PERIODIC_HASTE = 316, - TOTAL_AURAS = 317 + SPELL_AURA_PERIODIC_HASTE = 316, // Not used in 4.3.4 (name from 3.3.5a) + SPELL_AURA_MOD_SPELL_POWER_PCT = 317, + SPELL_AURA_MASTERY = 318, + SPELL_AURA_MOD_MELEE_HASTE_3 = 319, + SPELL_AURA_MOD_RANGED_HASTE_2 = 320, + SPELL_AURA_321 = 321, + SPELL_AURA_INTERFERE_TARGETTING = 322, // NYI + SPELL_AURA_323 = 323, // Not used in 4.3.4 + SPELL_AURA_324 = 324, // spell critical chance (probably by school mask) + SPELL_AURA_325 = 325, // Not used in 4.3.4 + SPELL_AURA_PHASE_GROUP = 326, // Puts the player in all the phases that are in the group with id = miscB + SPELL_AURA_327 = 327, // Not used in 4.3.4 + SPELL_AURA_PROC_ON_POWER_AMOUNT = 328, + SPELL_AURA_MOD_RUNE_REGEN_SPEED = 329, // NYI + SPELL_AURA_CAST_WHILE_WALKING = 330, + SPELL_AURA_FORCE_WEATHER = 331, + SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS = 332, + SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2 = 333, + SPELL_AURA_MOD_BLIND = 334, // NYI + SPELL_AURA_335 = 335, + SPELL_AURA_MOD_FLYING_RESTRICTIONS = 336, // NYI + SPELL_AURA_MOD_VENDOR_ITEMS_PRICES = 337, + SPELL_AURA_MOD_DURABILITY_LOSS = 338, + SPELL_AURA_INCREASE_SKILL_GAIN_CHANCE = 339, // NYI + SPELL_AURA_MOD_RESURRECTED_HEALTH_BY_GUILD_MEMBER = 340, // Increases health gained when resurrected by a guild member by X + SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN = 341, // Modifies cooldown of all spells using affected category + SPELL_AURA_MOD_MELEE_RANGED_HASTE_2 = 342, + SPELL_AURA_343 = 343, + SPELL_AURA_MOD_AUTOATTACK_DAMAGE = 344, // NYI + SPELL_AURA_BYPASS_ARMOR_FOR_CASTER = 345, + SPELL_AURA_ENABLE_ALT_POWER = 346, // NYI + SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE = 347, // NYI + SPELL_AURA_DEPOSIT_BONUS_MONEY_IN_GUILD_BANK_ON_LOOT = 348, + SPELL_AURA_MOD_CURRENCY_GAIN = 349, + SPELL_AURA_MOD_GATHERING_ITEMS_GAINED_PERCENT = 350, // NYI + SPELL_AURA_351 = 351, + SPELL_AURA_352 = 352, + SPELL_AURA_MOD_CAMOUFLAGE = 353, // NYI + SPELL_AURA_354 = 354, // Restoration Shaman mastery - mod healing based on target's health (less = more healing) + SPELL_AURA_355 = 355, + SPELL_AURA_356 = 356, // Arcane Mage mastery - mod damage based on current mana + SPELL_AURA_ENABLE_BOSS1_UNIT_FRAME = 357, + SPELL_AURA_WORGEN_ALTERED_FORM = 358, + SPELL_AURA_359 = 359, + SPELL_AURA_PROC_TRIGGER_SPELL_COPY = 360, // Procs the same spell that caused this proc (Dragonwrath, Tarecgosa's Rest) + SPELL_AURA_PROC_TRIGGER_SPELL_2 = 361, + SPELL_AURA_362 = 362, // Not used in 4.3.4 + SPELL_AURA_MOD_NEXT_SPELL = 363, // Used by 101601 Throw Totem - causes the client to initialize spell cast with specified spell + SPELL_AURA_364 = 364, // Not used in 4.3.4 + SPELL_AURA_MAX_FAR_CLIP_PLANE = 365, // Overrides client's View Distance setting to max("Fair", current_setting) and turns off terrain display + SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT = 366, // NYI - Sets spellpower equal to % of attack power, discarding all other bonuses (from gear and buffs) + SPELL_AURA_367 = 367, + SPELL_AURA_368 = 368, // Not used in 4.3.4 + SPELL_AURA_ENABLE_POWER_BAR_TIMER = 369, + SPELL_AURA_SET_FAIR_FAR_CLIP = 370, // Overrides client's View Distance setting to max("Fair", current_setting) + TOTAL_AURAS = 371 // 4.3.4 }; enum AuraObjectType diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 1894776c990..da12ed3da77 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -38,6 +38,7 @@ #include "Vehicle.h" #include "Battlefield.h" #include "BattlefieldMgr.h" +#include "WeatherMgr.h" #include "Pet.h" #include "ReputationMgr.h" @@ -76,7 +77,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH &AuraEffect::HandleModStealthDetect, // 17 SPELL_AURA_MOD_DETECT &AuraEffect::HandleModInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY - &AuraEffect::HandleModInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION + &AuraEffect::HandleModInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECT &AuraEffect::HandleNoImmediateEffect, // 20 SPELL_AURA_OBS_MOD_HEALTH implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, // 21 SPELL_AURA_OBS_MOD_POWER implemented in AuraEffect::PeriodicTick &AuraEffect::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE @@ -120,7 +121,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleAuraModPacifyAndSilence, // 60 SPELL_AURA_MOD_PACIFY_SILENCE &AuraEffect::HandleAuraModScale, // 61 SPELL_AURA_MOD_SCALE &AuraEffect::HandleNoImmediateEffect, // 62 SPELL_AURA_PERIODIC_HEALTH_FUNNEL implemented in AuraEffect::PeriodicTick - &AuraEffect::HandleUnused, // 63 unused (3.2.0) old SPELL_AURA_PERIODIC_MANA_FUNNEL + &AuraEffect::HandleUnused, // 63 unused (4.3.4) old SPELL_AURA_PERIODIC_MANA_FUNNEL &AuraEffect::HandleNoImmediateEffect, // 64 SPELL_AURA_PERIODIC_MANA_LEECH implemented in AuraEffect::PeriodicTick &AuraEffect::HandleModCastingSpeed, // 65 SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK &AuraEffect::HandleFeignDeath, // 66 SPELL_AURA_FEIGN_DEATH @@ -147,7 +148,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, // 87 SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus &AuraEffect::HandleNoImmediateEffect, // 88 SPELL_AURA_MOD_HEALTH_REGEN_PERCENT implemented in Player::RegenerateHealth &AuraEffect::HandleNoImmediateEffect, // 89 SPELL_AURA_PERIODIC_DAMAGE_PERCENT - &AuraEffect::HandleUnused, // 90 unused (3.0.8a) old SPELL_AURA_MOD_RESIST_CHANCE + &AuraEffect::HandleUnused, // 90 unused (4.3.4) old SPELL_AURA_MOD_RESIST_CHANCE &AuraEffect::HandleNoImmediateEffect, // 91 SPELL_AURA_MOD_DETECT_RANGE implemented in Creature::GetAttackDistance &AuraEffect::HandlePreventFleeing, // 92 SPELL_AURA_PREVENTS_FLEEING &AuraEffect::HandleModUnattackable, // 93 SPELL_AURA_MOD_UNATTACKABLE @@ -176,7 +177,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //116 SPELL_AURA_MOD_REGEN_DURING_COMBAT &AuraEffect::HandleNoImmediateEffect, //117 SPELL_AURA_MOD_MECHANIC_RESISTANCE implemented in Unit::MagicSpellHitResult &AuraEffect::HandleNoImmediateEffect, //118 SPELL_AURA_MOD_HEALING_PCT implemented in Unit::SpellHealingBonus - &AuraEffect::HandleUnused, //119 unused (3.2.0) old SPELL_AURA_SHARE_PET_TRACKING + &AuraEffect::HandleUnused, //119 unused (4.3.4) old SPELL_AURA_SHARE_PET_TRACKING &AuraEffect::HandleAuraUntrackable, //120 SPELL_AURA_UNTRACKABLE &AuraEffect::HandleAuraEmpathy, //121 SPELL_AURA_EMPATHY &AuraEffect::HandleModOffhandDamagePercent, //122 SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT @@ -198,7 +199,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleModMeleeSpeedPct, //138 SPELL_AURA_MOD_MELEE_HASTE &AuraEffect::HandleForceReaction, //139 SPELL_AURA_FORCE_REACTION &AuraEffect::HandleAuraModRangedHaste, //140 SPELL_AURA_MOD_RANGED_HASTE - &AuraEffect::HandleRangedAmmoHaste, //141 SPELL_AURA_MOD_RANGED_AMMO_HASTE + &AuraEffect::HandleUnused, //141 SPELL_AURA_141 &AuraEffect::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT &AuraEffect::HandleAuraModResistanceExclusive, //143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE &AuraEffect::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes @@ -210,14 +211,14 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT &AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED &AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance - &AuraEffect::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT + &AuraEffect::HandleUnused, //153 Unused (4.3.4) old SPELL_AURA_SPLIT_DAMAGE_FLAT &AuraEffect::HandleModStealthLevel, //154 SPELL_AURA_MOD_STEALTH_LEVEL &AuraEffect::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING &AuraEffect::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN &AuraEffect::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI &AuraEffect::HandleShieldBlockValue, //158 SPELL_AURA_MOD_SHIELD_BLOCKVALUE &AuraEffect::HandleNoImmediateEffect, //159 SPELL_AURA_NO_PVP_CREDIT only for Honorless Target spell - &AuraEffect::HandleNoImmediateEffect, //160 SPELL_AURA_MOD_AOE_AVOIDANCE implemented in Unit::MagicSpellHitResult + &AuraEffect::HandleUnused, //160 Unused (4.3.4) old SPELL_AURA_MOD_AOE_AVOIDANCE &AuraEffect::HandleNoImmediateEffect, //161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT &AuraEffect::HandleNoImmediateEffect, //162 SPELL_AURA_POWER_BURN implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS @@ -226,19 +227,19 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleAuraModAttackPowerPercent, //166 SPELL_AURA_MOD_ATTACK_POWER_PCT &AuraEffect::HandleAuraModRangedAttackPowerPercent, //167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT &AuraEffect::HandleNoImmediateEffect, //168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus - &AuraEffect::HandleNoImmediateEffect, //169 SPELL_AURA_MOD_CRIT_PERCENT_VERSUS implemented in Unit::DealDamageBySchool, Unit::DoAttackDamage, Unit::SpellCriticalBonus + &AuraEffect::HandleUnused, //169 Unused (4.3.4) old SPELL_AURA_MOD_CRIT_PERCENT_VERSUS &AuraEffect::HandleNULL, //170 SPELL_AURA_DETECT_AMORE various spells that change visual of units for aura target (clientside?) &AuraEffect::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK &AuraEffect::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK - &AuraEffect::HandleUnused, //173 unused (3.2.0) no spells, old SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell + &AuraEffect::HandleUnused, //173 unused (4.3.4) no spells, old SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell &AuraEffect::HandleModSpellDamagePercentFromStat, //174 SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT implemented in Unit::SpellBaseDamageBonus &AuraEffect::HandleModSpellHealingPercentFromStat, //175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT implemented in Unit::SpellBaseHealingBonus &AuraEffect::HandleSpiritOfRedemption, //176 SPELL_AURA_SPIRIT_OF_REDEMPTION only for Spirit of Redemption spell, die at aura end &AuraEffect::HandleCharmConvert, //177 SPELL_AURA_AOE_CHARM - &AuraEffect::HandleNoImmediateEffect, //178 SPELL_AURA_MOD_DEBUFF_RESISTANCE implemented in Unit::MagicSpellHitResult + &AuraEffect::HandleUnused, //178 old SPELL_AURA_MOD_DEBUFF_RESISTANCE unused 4.3.4 &AuraEffect::HandleNoImmediateEffect, //179 SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE implemented in Unit::SpellCriticalBonus &AuraEffect::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonus - &AuraEffect::HandleUnused, //181 unused (3.2.0) old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS + &AuraEffect::HandleUnused, //181 unused (4.3.4) old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS &AuraEffect::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT &AuraEffect::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746 - miscvalue - spell school &AuraEffect::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst @@ -255,8 +256,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //195 SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist &AuraEffect::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN - flat mod of spell cooldowns &AuraEffect::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::GetUnitCriticalChance - &AuraEffect::HandleUnused, //198 unused (3.2.0) old SPELL_AURA_MOD_ALL_WEAPON_SKILLS - &AuraEffect::HandleNoImmediateEffect, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT implemented in Unit::MagicSpellHitResult + &AuraEffect::HandleUnused, //198 unused (4.3.4) old SPELL_AURA_MOD_ALL_WEAPON_SKILLS + &AuraEffect::HandleUnused, //199 unused (4.3.4) old SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT &AuraEffect::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_XP_PCT implemented in Player::RewardPlayerAndGroupAtKill &AuraEffect::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode... &AuraEffect::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst @@ -269,19 +270,19 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleAuraModIncreaseFlightSpeed, //209 SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS &AuraEffect::HandleAuraModIncreaseFlightSpeed, //210 SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS &AuraEffect::HandleAuraModIncreaseFlightSpeed, //211 SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK - &AuraEffect::HandleAuraModRangedAttackPowerOfStatPercent, //212 SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT + &AuraEffect::HandleUnused, //212 Unused (4.3.4) old SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT &AuraEffect::HandleNoImmediateEffect, //213 SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT implemented in Player::RewardRage &AuraEffect::HandleNULL, //214 Tamed Pet Passive &AuraEffect::HandleArenaPreparation, //215 SPELL_AURA_ARENA_PREPARATION &AuraEffect::HandleModCastingSpeed, //216 SPELL_AURA_HASTE_SPELLS - &AuraEffect::HandleNULL, //217 69106 - killing spree helper - unknown use + &AuraEffect::HandleModMeleeSpeedPct, //217 SPELL_AURA_MOD_MELEE_HASTE_2 &AuraEffect::HandleAuraModRangedHaste, //218 SPELL_AURA_HASTE_RANGED &AuraEffect::HandleModManaRegen, //219 SPELL_AURA_MOD_MANA_REGEN_FROM_STAT &AuraEffect::HandleModRatingFromStat, //220 SPELL_AURA_MOD_RATING_FROM_STAT &AuraEffect::HandleNULL, //221 SPELL_AURA_MOD_DETAUNT &AuraEffect::HandleUnused, //222 unused (3.2.0) only for spell 44586 that not used in real spell cast &AuraEffect::HandleNoImmediateEffect, //223 SPELL_AURA_RAID_PROC_FROM_CHARGE - &AuraEffect::HandleUnused, //224 unused (3.0.8a) + &AuraEffect::HandleUnused, //224 unused (4.3.4) &AuraEffect::HandleNoImmediateEffect, //225 SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE &AuraEffect::HandleNoImmediateEffect, //226 SPELL_AURA_PERIODIC_DUMMY implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, //227 SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE implemented in AuraEffect::PeriodicTick @@ -316,28 +317,28 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoReagentUseAura, //256 SPELL_AURA_NO_REAGENT_USE Use SpellClassMask for spell select &AuraEffect::HandleNULL, //257 SPELL_AURA_MOD_TARGET_RESIST_BY_SPELL_CLASS Use SpellClassMask for spell select &AuraEffect::HandleNULL, //258 SPELL_AURA_MOD_SPELL_VISUAL - &AuraEffect::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_HOT_PCT implemented in Unit::SpellHealingBonus + &AuraEffect::HandleUnused, //259 unused (4.3.4) old SPELL_AURA_MOD_HOT_PCT &AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code &AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast &AuraEffect::HandleAuraAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask &AuraEffect::HandleUnused, //264 unused (3.2.0) - &AuraEffect::HandleUnused, //265 unused (3.2.0) - &AuraEffect::HandleUnused, //266 unused (3.2.0) + &AuraEffect::HandleUnused, //265 unused (4.3.4) + &AuraEffect::HandleUnused, //266 unused (4.3.4) &AuraEffect::HandleNoImmediateEffect, //267 SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL implemented in Unit::IsImmunedToSpellEffect - &AuraEffect::HandleAuraModAttackPowerOfStatPercent, //268 SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT + &AuraEffect::HandleUnused, //268 unused (4.3.4) old SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT. &AuraEffect::HandleNoImmediateEffect, //269 SPELL_AURA_MOD_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage - &AuraEffect::HandleNoImmediateEffect, //270 SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage + &AuraEffect::HandleUnused, //270 unused (4.3.4) old SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST &AuraEffect::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonus &AuraEffect::HandleNoImmediateEffect, //272 SPELL_AURA_IGNORE_MELEE_RESET &AuraEffect::HandleUnused, //273 clientside - &AuraEffect::HandleNoImmediateEffect, //274 SPELL_AURA_CONSUME_NO_AMMO implemented in spell::CalculateDamageDoneForAllTargets + &AuraEffect::HandleUnused, //274 unused (4.3.4) &AuraEffect::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select &AuraEffect::HandleNULL, //276 mod damage % mechanic? - &AuraEffect::HandleNoImmediateEffect, //277 SPELL_AURA_MOD_ABILITY_AFFECTED_TARGETS implemented in spell::settargetmap + &AuraEffect::HandleUnused, //277 unused (4.3.4) old SPELL_AURA_MOD_MAX_AFFECTED_TARGETS &AuraEffect::HandleAuraModDisarm, //278 SPELL_AURA_MOD_DISARM_RANGED disarm ranged weapon &AuraEffect::HandleNoImmediateEffect, //279 SPELL_AURA_INITIALIZE_IMAGES - &AuraEffect::HandleNoImmediateEffect, //280 SPELL_AURA_MOD_TARGET_ARMOR_PCT + &AuraEffect::HandleUnused, //280 unused (4.3.4) old SPELL_AURA_MOD_ARMOR_PENETRATION_PCT &AuraEffect::HandleNoImmediateEffect, //281 SPELL_AURA_MOD_HONOR_GAIN_PCT implemented in Player::RewardHonor &AuraEffect::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT &AuraEffect::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus @@ -352,28 +353,82 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleAuraOpenStable, //292 SPELL_AURA_OPEN_STABLE &AuraEffect::HandleAuraOverrideSpells, //293 SPELL_AURA_OVERRIDE_SPELLS auras which probably add set of abilities to their target based on it's miscvalue &AuraEffect::HandleNoImmediateEffect, //294 SPELL_AURA_PREVENT_REGENERATE_POWER implemented in Player::Regenerate(Powers power) - &AuraEffect::HandleUnused, //295 0 spells in 3.3.5 + &AuraEffect::HandleUnused, //295 unused (4.3.4) &AuraEffect::HandleAuraSetVehicle, //296 SPELL_AURA_SET_VEHICLE_ID sets vehicle on target &AuraEffect::HandleNULL, //297 Spirit Burst spells &AuraEffect::HandleNULL, //298 70569 - Strangulating, maybe prevents talk or cast - &AuraEffect::HandleUnused, //299 unused + &AuraEffect::HandleUnused, //299 unused (4.3.4) &AuraEffect::HandleNoImmediateEffect, //300 SPELL_AURA_SHARE_DAMAGE_PCT implemented in Unit::DealDamage &AuraEffect::HandleNoImmediateEffect, //301 SPELL_AURA_SCHOOL_HEAL_ABSORB implemented in Unit::CalcHealAbsorb - &AuraEffect::HandleUnused, //302 0 spells in 3.3.5 + &AuraEffect::HandleUnused, //302 unused (4.3.4) &AuraEffect::HandleNoImmediateEffect, //303 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus &AuraEffect::HandleAuraModFakeInebriation, //304 SPELL_AURA_MOD_DRUNK &AuraEffect::HandleAuraModIncreaseSpeed, //305 SPELL_AURA_MOD_MINIMUM_SPEED - &AuraEffect::HandleUnused, //306 0 spells in 3.3.5 - &AuraEffect::HandleUnused, //307 0 spells in 3.3.5 + &AuraEffect::HandleUnused, //306 unused (4.3.4) + &AuraEffect::HandleUnused, //307 unused (4.3.4) &AuraEffect::HandleNULL, //308 new aura for hunter traps - &AuraEffect::HandleUnused, //309 0 spells in 3.3.5 + &AuraEffect::HandleUnused, //309 unused (4.3.4) &AuraEffect::HandleNoImmediateEffect, //310 SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE implemented in Spell::CalculateDamageDone &AuraEffect::HandleNULL, //311 0 spells in 3.3.5 &AuraEffect::HandleNULL, //312 0 spells in 3.3.5 - &AuraEffect::HandleUnused, //313 0 spells in 3.3.5 + &AuraEffect::HandleUnused, //313 unused (4.3.4) &AuraEffect::HandlePreventResurrection, //314 SPELL_AURA_PREVENT_RESURRECTION todo &AuraEffect::HandleNoImmediateEffect, //315 SPELL_AURA_UNDERWATER_WALKING todo - &AuraEffect::HandleNoImmediateEffect, //316 SPELL_AURA_PERIODIC_HASTE implemented in AuraEffect::CalculatePeriodic + &AuraEffect::HandleNoImmediateEffect, //316 unused (4.3.4) old SPELL_AURA_PERIODIC_HASTE + &AuraEffect::HandleNULL, //317 SPELL_AURA_MOD_SPELL_POWER_PCT + &AuraEffect::HandleMastery, //318 SPELL_AURA_MASTERY + &AuraEffect::HandleModMeleeSpeedPct, //319 SPELL_AURA_MOD_MELEE_HASTE_3 + &AuraEffect::HandleAuraModRangedHaste, //320 SPELL_AURA_MOD_RANGED_HASTE_2 + &AuraEffect::HandleNULL, //321 SPELL_AURA_321 + &AuraEffect::HandleNULL, //322 SPELL_AURA_INTERFERE_TARGETTING + &AuraEffect::HandleUnused, //323 unused (4.3.4) + &AuraEffect::HandleNULL, //324 SPELL_AURA_324 + &AuraEffect::HandleUnused, //325 unused (4.3.4) + &AuraEffect::HandlePhaseGroup, //326 SPELL_AURA_PHASE_GROUP + &AuraEffect::HandleUnused, //327 unused (4.3.4) + &AuraEffect::HandleNoImmediateEffect, //328 SPELL_AURA_PROC_ON_POWER_AMOUNT implemented in Unit::HandleAuraProcOnPowerAmount + &AuraEffect::HandleNULL, //329 SPELL_AURA_MOD_RUNE_REGEN_SPEED + &AuraEffect::HandleNoImmediateEffect, //330 SPELL_AURA_CAST_WHILE_WALKING + &AuraEffect::HandleAuraForceWeather, //331 SPELL_AURA_FORCE_WEATHER + &AuraEffect::HandleNoImmediateEffect, //332 SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS implemented in WorldSession::HandleCastSpellOpcode + &AuraEffect::HandleNoImmediateEffect, //333 SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2 implemented in WorldSession::HandleCastSpellOpcode + &AuraEffect::HandleNULL, //334 SPELL_AURA_MOD_BLIND + &AuraEffect::HandleNULL, //335 SPELL_AURA_335 + &AuraEffect::HandleNULL, //336 SPELL_AURA_MOD_FLYING_RESTRICTIONS + &AuraEffect::HandleNoImmediateEffect, //337 SPELL_AURA_MOD_VENDOR_ITEMS_PRICES + &AuraEffect::HandleNoImmediateEffect, //338 SPELL_AURA_MOD_DURABILITY_LOSS + &AuraEffect::HandleNULL, //339 SPELL_AURA_INCREASE_SKILL_GAIN_CHANCE + &AuraEffect::HandleNULL, //340 SPELL_AURA_MOD_RESURRECTED_HEALTH_BY_GUILD_MEMBER + &AuraEffect::HandleNULL, //341 SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN + &AuraEffect::HandleModMeleeRangedSpeedPct, //342 SPELL_AURA_MOD_MELEE_RANGED_HASTE_2 + &AuraEffect::HandleNULL, //343 SPELL_AURA_343 + &AuraEffect::HandleNULL, //344 SPELL_AURA_MOD_AUTOATTACK_DAMAGE + &AuraEffect::HandleNoImmediateEffect, //345 SPELL_AURA_BYPASS_ARMOR_FOR_CASTER + &AuraEffect::HandleEnableAltPower, //346 SPELL_AURA_ENABLE_ALT_POWER + &AuraEffect::HandleNULL, //347 SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE + &AuraEffect::HandleNoImmediateEffect, //348 SPELL_AURA_DEPOSIT_BONUS_MONEY_IN_GUILD_BANK_ON_LOOT implemented in WorldSession::HandleLootMoneyOpcode + &AuraEffect::HandleNoImmediateEffect, //349 SPELL_AURA_MOD_CURRENCY_GAIN implemented in Player::ModifyCurrency + &AuraEffect::HandleNULL, //350 SPELL_AURA_MOD_GATHERING_ITEMS_GAINED_PERCENT + &AuraEffect::HandleNULL, //351 SPELL_AURA_351 + &AuraEffect::HandleNULL, //352 SPELL_AURA_352 + &AuraEffect::HandleNULL, //353 SPELL_AURA_MOD_CAMOUFLAGE + &AuraEffect::HandleNULL, //354 SPELL_AURA_354 + &AuraEffect::HandleUnused, //355 unused (4.3.4) + &AuraEffect::HandleNULL, //356 SPELL_AURA_356 + &AuraEffect::HandleNULL, //357 SPELL_AURA_ENABLE_BOSS1_UNIT_FRAME + &AuraEffect::HandleNULL, //358 SPELL_AURA_358 + &AuraEffect::HandleNULL, //359 SPELL_AURA_359 + &AuraEffect::HandleNULL, //360 SPELL_AURA_PROC_TRIGGER_SPELL_COPY + &AuraEffect::HandleNULL, //361 SPELL_AURA_PROC_TRIGGER_SPELL_2 implemented in Unit::ProcDamageAndSpellFor + &AuraEffect::HandleUnused, //362 unused (4.3.4) + &AuraEffect::HandleNULL, //363 SPELL_AURA_MOD_NEXT_SPELL + &AuraEffect::HandleUnused, //364 unused (4.3.4) + &AuraEffect::HandleNULL, //365 SPELL_AURA_MAX_FAR_CLIP_PLANE + &AuraEffect::HandleNULL, //366 SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT + &AuraEffect::HandleNULL, //367 SPELL_AURA_367 + &AuraEffect::HandleUnused, //368 unused (4.3.4) + &AuraEffect::HandleNULL, //369 SPELL_AURA_ENABLE_POWER_BAR_TIMER + &AuraEffect::HandleNULL, //370 SPELL_AURA_SET_FAIR_FAR_CLIP }; AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster): @@ -419,7 +474,12 @@ void AuraEffect::GetApplicationList(std::list<AuraApplication*> & applicationLis int32 AuraEffect::CalculateAmount(Unit* caster) { // default amount calculation - int32 amount = m_spellInfo->Effects[m_effIndex].CalcValue(caster, &m_baseAmount, NULL); + int32 amount = 0; + + if (!(m_spellInfo->AttributesEx8 & SPELL_ATTR8_MASTERY_SPECIALIZATION) || G3D::fuzzyEq(m_spellInfo->Effects[m_effIndex].BonusMultiplier, 0.0f)) + amount = m_spellInfo->Effects[m_effIndex].CalcValue(caster, &m_baseAmount, GetBase()->GetOwner()->ToUnit()); + else if (caster && caster->GetTypeId() == TYPEID_PLAYER) + amount = int32(caster->GetFloatValue(PLAYER_MASTERY) * m_spellInfo->Effects[m_effIndex].BonusMultiplier); // check item enchant aura cast if (!amount && caster) @@ -469,9 +529,9 @@ int32 AuraEffect::CalculateAmount(Unit* caster) Unit::AuraEffectList const& overrideClassScripts = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (Unit::AuraEffectList::const_iterator itr = overrideClassScripts.begin(); itr != overrideClassScripts.end(); ++itr) { - if ((*itr)->IsAffectedOnSpell(m_spellInfo)) + if ((*itr)->IsAffectingSpell(m_spellInfo)) { - // Glyph of Fear, Glyph of Frost nova and similar auras + // Glyph of Frost nova and similar auras if ((*itr)->GetMiscValue() == 7801) { AddPct(amount, (*itr)->GetAmount()); @@ -485,6 +545,45 @@ int32 AuraEffect::CalculateAmount(Unit* caster) case SPELL_AURA_MANA_SHIELD: m_canBeRecalculated = false; break; + case SPELL_AURA_MOUNTED: + if (MountCapabilityEntry const* mountCapability = GetBase()->GetUnitOwner()->GetMountCapability(uint32(GetMiscValueB()))) + { + amount = mountCapability->Id; + m_canBeRecalculated = false; + } + break; + case SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE: + { + if (caster) + { + // if Level <= 70 resist = player level + int32 resist = caster->getLevel(); + + if (resist > 70 && resist < 81) + resist += (resist - 70) * 5; + else if (resist > 80) + resist += ((resist-70) * 5 + (resist - 80) * 7); + + switch (GetId()) + { + case 20043: // Aspect of the Wild + case 8185: // Elemental Resistance + case 19891: // Resistance Aura + case 79106: // Shadow Protection + case 79107: // Shadow Protection + amount = resist; + break; + case 79060: // Mark of the Wild + case 79061: // Mark of the Wild + case 79062: // Blessing of Kings + case 79063: // Blessing of Kings + case 90363: // Embrace of the Shale Spider + amount = resist / 2; + break; + } + break; + } + } default: break; } @@ -494,7 +593,7 @@ int32 AuraEffect::CalculateAmount(Unit* caster) return amount; } -void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load) +void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= true*/, bool load /*= false*/) { m_amplitude = m_spellInfo->Effects[m_effIndex].Amplitude; @@ -545,8 +644,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load) if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) caster->ModSpellCastTime(m_spellInfo, m_amplitude); } - // and periodic time of auras affected by SPELL_AURA_PERIODIC_HASTE - else if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) + else if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) m_amplitude = int32(m_amplitude * caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); } } @@ -564,9 +662,6 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load) // reset periodic timer on aura create or on reapply when aura isn't dot // possibly we should not reset periodic timers only when aura is triggered by proc // or maybe there's a spell attribute somewhere - bool resetPeriodicTimer = create - || ((GetAuraType() != SPELL_AURA_PERIODIC_DAMAGE) && (GetAuraType() != SPELL_AURA_PERIODIC_DAMAGE_PERCENT)); - if (resetPeriodicTimer) { m_periodicTimer = 0; @@ -795,6 +890,16 @@ void AuraEffect::UpdatePeriodic(Unit* caster) case 49472: // Drink Coffee case 57073: case 61830: + case 69176: + case 72623: + case 80166: + case 80167: + case 87958: + case 87959: + case 92736: + case 92797: + case 92800: + case 92803: if (!caster || caster->GetTypeId() != TYPEID_PLAYER) return; // Get SPELL_AURA_MOD_POWER_REGEN aura from spell @@ -894,17 +999,11 @@ void AuraEffect::UpdatePeriodic(Unit* caster) bool AuraEffect::CanPeriodicTickCrit(Unit const* caster) const { ASSERT(caster); - if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, m_spellInfo)) - return true; - // Rupture - since 3.3.3 can crit - if (m_spellInfo->SpellIconID == 500 && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) - return true; - - return false; + return caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, m_spellInfo); } -bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const +bool AuraEffect::IsAffectingSpell(SpellInfo const* spell) const { if (!spell) return false; @@ -1030,14 +1129,11 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const { uint32 spellId = 0; uint32 spellId2 = 0; - //uint32 spellId3 = 0; - uint32 HotWSpellId = 0; switch (GetMiscValue()) { case FORM_CAT: spellId = 3025; - HotWSpellId = 24900; break; case FORM_TREE: spellId = 34123; @@ -1051,12 +1147,6 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const case FORM_BEAR: spellId = 1178; spellId2 = 21178; - HotWSpellId = 24899; - break; - case FORM_DIREBEAR: - spellId = 9635; - spellId2 = 21178; - HotWSpellId = 24899; break; case FORM_BATTLESTANCE: spellId = 21156; @@ -1069,7 +1159,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const break; case FORM_MOONKIN: spellId = 24905; - spellId2 = 69366; + spellId2 = 24907; break; case FORM_FLIGHT: spellId = 33948; @@ -1089,7 +1179,6 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const break; case FORM_SHADOW: spellId = 49868; - spellId2 = 71167; break; case FORM_GHOSTWOLF: spellId = 67116; @@ -1123,7 +1212,9 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (target->GetTypeId() == TYPEID_PLAYER) { - const PlayerSpellMap& sp_list = target->ToPlayer()->GetSpellMap(); + Player* plrTarget = target->ToPlayer(); + + PlayerSpellMap const& sp_list = plrTarget->GetSpellMap(); for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) { if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) @@ -1136,6 +1227,9 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE))) continue; + if ((spellInfo->AttributesEx8 & SPELL_ATTR8_MASTERY_SPECIALIZATION) && !plrTarget->IsCurrentSpecMasterySpell(spellInfo)) + continue; + if (spellInfo->Stances & (1<<(GetMiscValue()-1))) target->CastSpell(target, itr->first, true, NULL, this); } @@ -1143,49 +1237,52 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const // Also do it for Glyphs for (uint32 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) { - if (uint32 glyphId = target->ToPlayer()->GetGlyph(i)) + if (uint32 glyphId = plrTarget->GetGlyph(plrTarget->GetActiveSpec(), i)) { if (GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId)) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(glyph->SpellId); if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE))) continue; - if (spellInfo->Stances & (1<<(GetMiscValue()-1))) + + if (spellInfo->Stances & (1 << (GetMiscValue() - 1))) target->CastSpell(target, glyph->SpellId, true, NULL, this); } } } // Leader of the Pack - if (target->ToPlayer()->HasSpell(17007)) + if (plrTarget->HasSpell(17007)) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(24932); - if (spellInfo && spellInfo->Stances & (1<<(GetMiscValue()-1))) + if (spellInfo && spellInfo->Stances & (1 << (GetMiscValue() -1))) target->CastSpell(target, 24932, true, NULL, this); } - // Improved Barkskin - apply/remove armor bonus due to shapeshift - if (target->ToPlayer()->HasSpell(63410) || target->ToPlayer()->HasSpell(63411)) - { - target->RemoveAurasDueToSpell(66530); - if (GetMiscValue() == FORM_TRAVEL || GetMiscValue() == FORM_NONE) // "while in Travel Form or while not shapeshifted" - target->CastSpell(target, 66530, true); - } + // Heart of the Wild - if (HotWSpellId) - { // hacky, but the only way as spell family is not SPELLFAMILY_DRUID - Unit::AuraEffectList const& mModTotalStatPct = target->GetAuraEffectsByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE); - for (Unit::AuraEffectList::const_iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i) - { - // Heart of the Wild - if ((*i)->GetSpellInfo()->SpellIconID == 240 && (*i)->GetMiscValue() == 3) - { - int32 HotWMod = (*i)->GetAmount() / 2; // For each 2% Intelligence, you get 1% stamina and 1% attack power. + if (AuraEffect const* heartOfTheWild = target->GetAuraEffectOfRankedSpell(17003, EFFECT_0)) + { + uint32 heartOfTheWildSpellId = 0; + int32 heartOfTheWildAmount = 0; - target->CastCustomSpell(target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this); + switch (GetMiscValue()) + { + case FORM_CAT: + heartOfTheWildSpellId = 24900; + heartOfTheWildAmount = heartOfTheWild->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); + break; + case FORM_BEAR: + heartOfTheWildSpellId = 24899; + heartOfTheWildAmount = heartOfTheWild->GetSpellInfo()->Effects[EFFECT_2].CalcValue(); + break; + default: break; - } } + + if (heartOfTheWildSpellId) + target->CastCustomSpell(target, heartOfTheWildSpellId, &heartOfTheWildAmount, NULL, NULL, true, NULL, this); } + switch (GetMiscValue()) { case FORM_CAT: @@ -1193,7 +1290,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (target->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_DRUID, 0, 0x10000000, 0)) target->CastSpell(target, 62071, true); // Nurturing Instinct - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT, SPELLFAMILY_DRUID, 2254, 0)) + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT, SPELLFAMILY_DRUID, 2254, EFFECT_0)) { uint32 spellId3 = 0; switch (aurEff->GetId()) @@ -1208,43 +1305,36 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const target->CastSpell(target, spellId3, true, NULL, this); } // Master Shapeshifter - Cat - if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_HEALING_DONE_PERCENT, SPELLFAMILY_GENERIC, 2851, EFFECT_0)) { int32 bp = aurEff->GetAmount(); target->CastCustomSpell(target, 48420, &bp, NULL, NULL, true); } - break; - case FORM_DIREBEAR: + break; case FORM_BEAR: // Master Shapeshifter - Bear - if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_HEALING_DONE_PERCENT, SPELLFAMILY_GENERIC, 2851, EFFECT_0)) { int32 bp = aurEff->GetAmount(); target->CastCustomSpell(target, 48418, &bp, NULL, NULL, true); } // Survival of the Fittest - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DRUID, 961, 0)) + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DRUID, 961, EFFECT_0)) { - int32 bp = aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue(); + int32 bp = aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue(GetCaster()); target->CastCustomSpell(target, 62069, &bp, NULL, NULL, true, 0, this); } - break; + break; case FORM_MOONKIN: // Master Shapeshifter - Moonkin - if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_HEALING_DONE_PERCENT, SPELLFAMILY_GENERIC, 2851, EFFECT_0)) { int32 bp = aurEff->GetAmount(); target->CastCustomSpell(target, 48421, &bp, NULL, NULL, true); } - break; - // Master Shapeshifter - Tree of Life - case FORM_TREE: - if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) - { - int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48422, &bp, NULL, NULL, true); - } - break; + break; + default: + break; } } } @@ -1255,17 +1345,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (spellId2) target->RemoveOwnedAura(spellId2, target->GetGUID()); - // Improved Barkskin - apply/remove armor bonus due to shapeshift - if (Player* player=target->ToPlayer()) - { - if (player->HasSpell(63410) || player->HasSpell(63411)) - { - target->RemoveAurasDueToSpell(66530); - target->CastSpell(target, 66530, true); - } - } - - const Unit::AuraEffectList& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); + Unit::AuraEffectList const& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); AuraEffect* newAura = NULL; // Iterate through all the shapeshift auras that the target has, if there is another aura with SPELL_AURA_MOD_SHAPESHIFT, then this aura is being removed due to that one being applied for (Unit::AuraEffectList::const_iterator itr = shapeshifts.begin(); itr != shapeshifts.end(); ++itr) @@ -1276,11 +1356,12 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const break; } } + Unit::AuraApplicationMap& tAuras = target->GetAppliedAuras(); for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();) { // Use the new aura to see on what stance the target will be - uint32 newStance = (1<<((newAura ? newAura->GetMiscValue() : 0)-1)); + uint32 newStance = (1 << ((newAura ? newAura->GetMiscValue() : 0) -1)); // If the stances are not compatible with the spell, remove it if (itr->second->GetBase()->IsRemovedOnShapeLost(target) && !(itr->second->GetBase()->GetSpellInfo()->Stances & newStance)) @@ -1527,37 +1608,40 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app Unit* target = aurApp->GetTarget(); - // no-phase is also phase state so same code for apply and remove - uint32 newPhase = 0; - Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE); - if (!phases.empty()) - for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - newPhase |= (*itr)->GetMiscValue(); + std::set<uint32> const& oldPhases = target->GetPhases(); + target->SetInPhase(GetMiscValueB(), false, apply); + + // call functions which may have additional effects after chainging state of unit + // phase auras normally not expected at BG but anyway better check + if (apply) + { + // drop flag at invisibiliy in bg + target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + } if (Player* player = target->ToPlayer()) { - if (!newPhase) - newPhase = PHASEMASK_NORMAL; + if (player->IsInWorld()) + player->GetMap()->SendUpdateTransportVisibility(player, oldPhases); + player->UpdatePhasing(); + } + + // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) + if (target->IsVisible()) + target->UpdateObjectVisibility(); +} - // GM-mode have mask 0xFFFFFFFF - if (player->IsGameMaster()) - newPhase = 0xFFFFFFFF; +void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - player->SetPhaseMask(newPhase, false); - player->GetSession()->SendSetPhaseShift(newPhase); - } - else - { - if (!newPhase) - { - newPhase = PHASEMASK_NORMAL; - if (Creature* creature = target->ToCreature()) - if (CreatureData const* data = sObjectMgr->GetCreatureData(creature->GetDBTableGUIDLow())) - newPhase = data->phaseMask; - } + Unit* target = aurApp->GetTarget(); - target->SetPhaseMask(newPhase, false); - } + std::set<uint32> const& oldPhases = target->GetPhases(); + std::set<uint32> const& phases = GetPhasesForGroup(GetMiscValueB()); + for (auto phase : phases) + target->SetInPhase(phase, false, apply); // call functions which may have additional effects after chainging state of unit // phase auras normally not expected at BG but anyway better check @@ -1567,6 +1651,13 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); } + if (Player* player = target->ToPlayer()) + { + if (player->IsInWorld()) + player->GetMap()->SendUpdateTransportVisibility(player, oldPhases); + player->UpdatePhasing(); + } + // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) if (target->IsVisible()) target->UpdateObjectVisibility(); @@ -1595,7 +1686,6 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo break; case FORM_BEAR: // 0x05 - case FORM_DIREBEAR: // 0x08 case FORM_BATTLESTANCE: // 0x11 case FORM_DEFENSIVESTANCE: // 0x12 @@ -1645,7 +1735,6 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo case FORM_TRAVEL: case FORM_AQUA: case FORM_BEAR: - case FORM_DIREBEAR: case FORM_FLIGHT_EPIC: case FORM_FLIGHT: case FORM_MOONKIN: @@ -1671,47 +1760,26 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo if (PowerType != POWER_MANA) { - uint32 oldPower = target->GetPower(PowerType); + int32 oldPower = target->GetPower(PowerType); // reset power to default values only at power change if (target->getPowerType() != PowerType) target->setPowerType(PowerType); - switch (form) + if (form == FORM_CAT || form == FORM_BEAR) { - case FORM_CAT: - case FORM_BEAR: - case FORM_DIREBEAR: - { - // get furor proc chance - uint32 FurorChance = 0; - if (AuraEffect const* dummy = target->GetDummyAuraEffect(SPELLFAMILY_DRUID, 238, 0)) - FurorChance = std::max(dummy->GetAmount(), 0); + // get furor proc chance + int32 FurorChance = 0; + if (AuraEffect const* dummy = target->GetDummyAuraEffect(SPELLFAMILY_DRUID, 238, 0)) + FurorChance = std::max(dummy->GetAmount(), 0); - switch (GetMiscValue()) - { - case FORM_CAT: - { - int32 basePoints = int32(std::min(oldPower, FurorChance)); - target->SetPower(POWER_ENERGY, 0); - target->CastCustomSpell(target, 17099, &basePoints, NULL, NULL, true, NULL, this); - break; - } - case FORM_BEAR: - case FORM_DIREBEAR: - if (urand(0, 99) < FurorChance) - target->CastSpell(target, 17057, true); - break; - default: - { - uint32 newEnergy = std::min(target->GetPower(POWER_ENERGY), FurorChance); - target->SetPower(POWER_ENERGY, newEnergy); - break; - } - } - break; + if (form == FORM_CAT) + { + int32 basePoints = std::min<int32>(oldPower, FurorChance); + target->SetPower(POWER_ENERGY, 0); + target->CastCustomSpell(target, 17099, &basePoints, NULL, NULL, true, NULL, this); } - default: - break; + else if (roll_chance_i(FurorChance)) + target->CastSpell(target, 17057, true); } } // stop handling the effect if it was removed by linked event @@ -1748,7 +1816,6 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo { // Nordrassil Harness - bonus case FORM_BEAR: - case FORM_DIREBEAR: case FORM_CAT: if (AuraEffect* dummy = target->GetAuraEffect(37315, 0)) target->CastSpell(target, 37316, true, NULL, dummy); @@ -1762,7 +1829,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo case FORM_DEFENSIVESTANCE: case FORM_BERSERKERSTANCE: { - uint32 Rage_val = 0; + int32 Rage_val = 0; // Defensive Tactics if (form == FORM_DEFENSIVESTANCE) { @@ -1811,9 +1878,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo if (!target->CanUseAttackType(BASE_ATTACK)) { if (Item* pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)) - { target->ToPlayer()->_ApplyWeaponDamage(EQUIPMENT_SLOT_MAINHAND, pItem->GetTemplate(), NULL, apply); - } } } @@ -1823,10 +1888,10 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo if (target->GetTypeId() == TYPEID_PLAYER) { - SpellShapeshiftEntry const* shapeInfo = sSpellShapeshiftStore.LookupEntry(form); + SpellShapeshiftFormEntry const* shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form); ASSERT(shapeInfo); // Learn spells for shapeshift form - no need to send action bars or add spells to spellbook - for (uint8 i = 0; i<MAX_SHAPESHIFT_SPELLS; ++i) + for (uint8 i = 0; i < MAX_SHAPESHIFT_SPELLS; ++i) { if (!shapeInfo->stanceSpell[i]) continue; @@ -2110,9 +2175,7 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo if (apply) { /* - WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); - data << target->GetGUID(); - data << uint8(0); + WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 0); target->SendMessageToSet(&data, true); */ @@ -2158,9 +2221,7 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo else { /* - WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); - data << target->GetGUID(); - data << uint8(1); + WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 0); target->SendMessageToSet(&data, true); */ @@ -2204,8 +2265,8 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, AuraType type = GetAuraType(); - //Prevent handling aura twice - if ((apply) ? target->GetAuraEffectsByType(type).size() > 1 : target->HasAuraType(type)) + // Prevent handling aura twice + if (apply ? target->GetAuraEffectsByType(type).size() > 1 : target->HasAuraType(type)) return; uint32 field, flag, slot; @@ -2476,17 +2537,18 @@ void AuraEffect::HandleAuraModSkill(AuraApplication const* aurApp, uint8 mode, b { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_SKILL))) return; - Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) + Player* target = aurApp->GetTarget()->ToPlayer(); + if (!target) return; uint32 prot = GetMiscValue(); int32 points = GetAmount(); - target->ToPlayer()->ModifySkillBonus(prot, ((apply) ? points: -points), GetAuraType() == SPELL_AURA_MOD_SKILL_TALENT); if (prot == SKILL_DEFENSE) - target->ToPlayer()->UpdateDefenseBonusesMod(); + return; + + target->ModifySkillBonus(prot, (apply ? points : -points), GetAuraType() == SPELL_AURA_MOD_SKILL_TALENT); } /****************************/ @@ -2530,6 +2592,11 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo } target->Mount(displayId, vehicleId, creatureEntry); + + // cast speed aura + if (mode & AURA_EFFECT_HANDLE_REAL) + if (MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(GetAmount())) + target->CastSpell(target, mountCapability->SpeedModSpell, true); } else { @@ -2538,7 +2605,13 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo // need to remove ALL arura related to mounts, this will stop client crash with broom stick // and never endless flying after using Headless Horseman's Mount if (mode & AURA_EFFECT_HANDLE_REAL) + { target->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // remove speed aura + if (MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(GetAmount())) + target->RemoveAurasDueToSpell(mountCapability->SpeedModSpell, target->GetGUID()); + } } } @@ -3704,12 +3777,6 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - if (GetMiscValue() < -1 || GetMiscValue() > 4) - { - TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); - return; - } - Unit* target = aurApp->GetTarget(); int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, -1); if (abs(spellGroupVal) >= abs(GetAmount())) @@ -3734,7 +3801,7 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) { - if (GetMiscValue() == i || GetMiscValue() == -1) + if (GetMiscValueB() & 1 << i || !GetMiscValueB()) // 0 is also used for all stats { int32 spellGroupVal2 = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, i); if (abs(spellGroupVal2) >= abs(GetAmount())) @@ -3755,7 +3822,7 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 // recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_UNK4 0x00000010 flag) // this check is total bullshit i think - if (GetMiscValue() == STAT_STAMINA && (m_spellInfo->Attributes & SPELL_ATTR0_ABILITY)) + if (GetMiscValueB() & 1 << STAT_STAMINA && (m_spellInfo->Attributes & SPELL_ATTR0_ABILITY)) target->SetHealth(std::max<uint32>(uint32(healthPct * target->GetMaxHealth() * 0.01f), (alive ? 1 : 0))); } @@ -3811,7 +3878,7 @@ void AuraEffect::HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode, // Update manaregen value if (GetMiscValue() == POWER_MANA) target->ToPlayer()->UpdateManaRegen(); - else if (GetMiscValue() == POWER_RUNE) + else if (GetMiscValue() == POWER_RUNES) target->ToPlayer()->UpdateRuneRegen(RuneType(GetMiscValueB())); // other powers are not immediate effects - implemented in Player::Regenerate, Creature::Regenerate } @@ -4132,6 +4199,7 @@ void AuraEffect::HandleModMeleeRangedSpeedPct(AuraApplication const* aurApp, uin if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; + //! ToDo: Haste auras with the same handler _CAN'T_ stack together Unit* target = aurApp->GetTarget(); target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply); @@ -4178,6 +4246,7 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; + //! ToDo: Haste auras with the same handler _CAN'T_ stack together Unit* target = aurApp->GetTarget(); int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_MELEE_HASTE); if (abs(spellGroupVal) >= abs(GetAmount())) @@ -4197,24 +4266,12 @@ void AuraEffect::HandleAuraModRangedHaste(AuraApplication const* aurApp, uint8 m if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; + //! ToDo: Haste auras with the same handler _CAN'T_ stack together Unit* target = aurApp->GetTarget(); target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); } -void AuraEffect::HandleRangedAmmoHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); -} - /********************************/ /*** COMBAT RATING ***/ /********************************/ @@ -4302,23 +4359,6 @@ void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* au target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()), apply); } -void AuraEffect::HandleAuraModRangedAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - // Recalculate bonus - if (target->GetTypeId() == TYPEID_PLAYER && !(target->getClassMask() & CLASSMASK_WAND_USERS)) - target->ToPlayer()->UpdateAttackPowerAndDamage(true); -} - -void AuraEffect::HandleAuraModAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - HandleAuraModAttackPowerOfArmor(aurApp, mode, apply); -} - void AuraEffect::HandleAuraModAttackPowerOfArmor(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) @@ -4652,22 +4692,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool } break; } - case 55198: // Tidal Force - { - target->CastSpell(target, 55166, true, NULL, this); - // set 3 stacks and 3 charges (to make all auras not disappear at once) - Aura* owner_aura = target->GetAura(55166, GetCasterGUID()); - if (owner_aura) - { - // This aura lasts 2 sec, need this hack to properly proc spells - /// @todo drop aura charges for ApplySpellMod in ProcDamageAndSpell - GetBase()->SetDuration(owner_aura->GetDuration()); - // Make aura be not charged-this prevents removing charge on not crit spells - owner_aura->SetCharges(0); - owner_aura->SetStackAmount(owner_aura->GetSpellInfo()->StackAmount); - } - break; - } case 39850: // Rocket Blast if (roll_chance_i(20)) // backfire stun target->CastSpell(target, 51581, true, NULL, this); @@ -4693,10 +4717,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (caster) target->GetMotionMaster()->MoveFall(); break; - case 46699: // Requires No Ammo - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use - break; case 52916: // Honor Among Thieves if (target->GetTypeId() == TYPEID_PLAYER) if (Unit* spellTarget = ObjectAccessor::GetUnit(*target, target->ToPlayer()->GetComboTarget())) @@ -4789,8 +4809,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool case 60244: // Blood Parrot Despawn Aura target->CastSpell((Unit*)NULL, GetAmount(), true, NULL, this); break; - case 58600: // Restricted Flight Area - case 58730: // Restricted Flight Area + case 91604: // Restricted Flight Area if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) target->CastSpell(target, 58601, true); break; @@ -4998,15 +5017,6 @@ void AuraEffect::HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mod if (!plCaster->isHonorOrXPTarget(target) || (target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->isTappedBy(plCaster))) return; - - // If this is Drain Soul, check for Glyph of Drain Soul - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000)) - { - // Glyph of Drain Soul - chance to create an additional Soul Shard - if (AuraEffect* aur = caster->GetAuraEffect(58070, 0)) - if (roll_chance_i(aur->GetMiscValue())) - caster->CastSpell(caster, 58068, true, 0, aur); // We _could_ simply do ++count here, but Blizz does it this way :) - } } //Adding items @@ -5290,7 +5300,7 @@ void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) + if (!target->IsInWorld()) return; uint32 vehicleId = GetMiscValue(); @@ -5303,6 +5313,9 @@ void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, else if (target->GetVehicleKit()) target->RemoveVehicleKit(); + if (target->GetTypeId() != TYPEID_PLAYER) + return; + WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, target->GetPackGUID().size()+4); data.appendPackGUID(target->GetGUID()); data << uint32(apply ? vehicleId : 0); @@ -5326,6 +5339,18 @@ void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8 aurApp->GetTarget()->SetByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER); } +void AuraEffect::HandleMastery(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Player* target = aurApp->GetTarget()->ToPlayer(); + if (!target) + return; + + target->UpdateMastery(); +} + void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const { switch (GetSpellInfo()->SpellFamilyName) @@ -5397,23 +5422,6 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const } break; } - case SPELLFAMILY_ROGUE: - { - switch (GetSpellInfo()->Id) - { - // Master of Subtlety - case 31666: - if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) - target->RemoveAurasDueToSpell(31665); - break; - // Overkill - case 58428: - if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) - target->RemoveAurasDueToSpell(58427); - break; - } - break; - } case SPELLFAMILY_HUNTER: { // Explosive Shot @@ -5705,13 +5713,6 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) case 66882: target->CastCustomSpell(triggerSpellId, SPELLVALUE_RADIUS_MOD, (int32)((((float)m_tickNumber / 60) * 0.9f + 0.1f) * 10000 * 2 / 3), NULL, true, NULL, this); return; - // Beacon of Light - case 53563: - { - // area aura owner casts the spell - GetBase()->GetUnitOwner()->CastSpell(target, triggeredSpellInfo, true, 0, this, GetBase()->GetUnitOwner()->GetGUID()); - return; - } // Slime Spray - temporary here until preventing default effect works again // added on 9.10.2010 case 69508: @@ -5866,16 +5867,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000)) { if (caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target)) - { - if (roll_chance_i(20)) - { - caster->CastSpell(caster, 43836, true, 0, this); - // Glyph of Drain Soul - chance to create an additional Soul Shard - if (AuraEffect* aur = caster->GetAuraEffect(58070, 0)) - if (roll_chance_i(aur->GetMiscValue())) - caster->CastSpell(caster, 58068, true, 0, aur); - } - } + caster->CastSpell(caster, 95810, true, 0, this); } if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_GENERIC) { @@ -5912,8 +5904,9 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); int32 dmg = damage; + if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) - caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL); + caster->ApplyResilience(target, &dmg); damage = dmg; caster->CalcAbsorbResist(target, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, GetSpellInfo()); @@ -6000,7 +5993,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c int32 dmg = damage; if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) - caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL); + caster->ApplyResilience(target, &dmg); damage = dmg; caster->CalcAbsorbResist(target, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, m_spellInfo); @@ -6104,15 +6097,6 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const if (maxval) AddPct(TakenTotalMod, maxval); - // Healing over time taken percent - float minval_hot = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT); - if (minval_hot) - AddPct(TakenTotalMod, minval_hot); - - float maxval_hot = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT); - if (maxval_hot) - AddPct(TakenTotalMod, maxval_hot); - TakenTotalMod = std::max(TakenTotalMod, 0.0f); damage = uint32(target->CountPctFromMaxHealth(damage)); @@ -6162,7 +6146,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const // Health Funnel // damage caster for heal amount - if (target != caster && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL) + if (target != caster && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL && GetSpellInfo()->Id != 755) { uint32 funnelDamage = GetSpellInfo()->ManaPerSecond; // damage is not affected by spell power @@ -6219,10 +6203,6 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con TC_LOG_INFO("spells", "PeriodicTick: %u (TypeId: %u) power leech of %u (TypeId: %u) for %u dmg inflicted by %u", GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), drainAmount, GetId()); - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - if (powerType == POWER_MANA) - drainAmount -= target->GetSpellCritDamageReduction(drainAmount); - int32 drainedAmount = -target->ModifyPower(powerType, -drainAmount); float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); @@ -6340,10 +6320,6 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con // ignore negative values (can be result apply spellmods to aura damage int32 damage = std::max(m_amount, 0); - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - if (powerType == POWER_MANA) - damage -= target->GetSpellCritDamageReduction(damage); - uint32 gain = uint32(-target->ModifyPower(powerType, -damage)); float dmgMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster); @@ -6503,3 +6479,52 @@ void AuraEffect::HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurA TC_LOG_DEBUG("spells", "AuraEffect::HandleRaidProcFromChargeWithValueAuraProc: Triggering spell %u from aura %u proc", triggerSpellId, GetId()); target->CastCustomSpell(target, triggerSpellId, &value, NULL, NULL, true, NULL, this, GetCasterGUID()); } + +void AuraEffect::HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Player* target = aurApp->GetTarget()->ToPlayer(); + + if (!target) + return; + + if (apply) + { + WorldPacket data(SMSG_WEATHER, (4 + 4 + 1)); + + data << uint32(GetMiscValue()) << 1.0f << uint8(0); + target->GetSession()->SendPacket(&data); + } + else + { + // send weather for current zone + if (Weather* weather = WeatherMgr::FindWeather(target->GetZoneId())) + weather->SendWeatherUpdateToPlayer(target); + else + { + if (!WeatherMgr::AddWeather(target->GetZoneId())) + { + // send fine weather packet to remove old weather + WeatherMgr::SendFineWeatherUpdateToPlayer(target); + } + } + } +} + +void AuraEffect::HandleEnableAltPower(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + uint32 altPowerId = GetMiscValue(); + UnitPowerBarEntry const* powerEntry = sUnitPowerBarStore.LookupEntry(altPowerId); + if (!powerEntry) + return; + + if (apply) + aurApp->GetTarget()->SetMaxPower(POWER_ALTERNATE_POWER, powerEntry->MaxPower); + else + aurApp->GetTarget()->SetMaxPower(POWER_ALTERNATE_POWER, 0); +} diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 5eec9021291..700bbb10417 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -59,7 +59,7 @@ class AuraEffect void SetPeriodicTimer(int32 periodicTimer) { m_periodicTimer = periodicTimer; } int32 CalculateAmount(Unit* caster); - void CalculatePeriodic(Unit* caster, bool create = false, bool load = false); + void CalculatePeriodic(Unit* caster, bool resetPeriodicTimer = true, bool load = false); void CalculateSpellMod(); void ChangeAmount(int32 newAmount, bool mark = true, bool onStackOrReapply = false); void RecalculateAmount() { if (!CanBeRecalculated()) return; ChangeAmount(CalculateAmount(GetCaster()), false); } @@ -86,7 +86,7 @@ class AuraEffect bool IsPeriodic() const { return m_isPeriodic; } void SetPeriodic(bool isPeriodic) { m_isPeriodic = isPeriodic; } - bool IsAffectedOnSpell(SpellInfo const* spell) const; + bool IsAffectingSpell(SpellInfo const* spell) const; bool HasSpellClassMask() const { return m_spellInfo->Effects[m_effIndex].SpellClassMask; } void SendTickImmune(Unit* target, Unit* caster) const; @@ -144,6 +144,8 @@ class AuraEffect void HandleSpiritOfRedemption(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraGhost(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandlePhase(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, bool apply) const; + // unit model void HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, bool apply) const; @@ -252,7 +254,6 @@ class AuraEffect void HandleModAttackSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModRangedHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const; - void HandleRangedAmmoHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const; // combat rating void HandleModRating(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mode, bool apply) const; @@ -261,8 +262,6 @@ class AuraEffect void HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModRangedAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; - void HandleAuraModRangedAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; - void HandleAuraModAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModAttackPowerOfArmor(AuraApplication const* aurApp, uint8 mode, bool apply) const; // damage bonus void HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, bool apply) const; @@ -290,6 +289,9 @@ class AuraEffect void HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandlePreventResurrection(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleMastery(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleEnableAltPower(AuraApplication const* aurApp, uint8 mode, bool apply) const; // aura effect periodic tick handlers void HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 851d992d857..e38dc8fdf4a 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -147,6 +147,9 @@ void AuraApplication::_InitFlags(Unit* caster, uint8 effMask) } _flags |= positiveFound ? AFLAG_POSITIVE : AFLAG_NEGATIVE; } + + if (GetBase()->GetSpellInfo()->AttributesEx8 & SPELL_ATTR8_AURA_SEND_AMOUNT) + _flags |= AFLAG_ANY_EFFECT_AMOUNT_SENT; } void AuraApplication::_HandleEffect(uint8 effIndex, bool apply) @@ -192,7 +195,7 @@ void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const uint32 flags = _flags; if (aura->GetMaxDuration() > 0 && !(aura->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_HIDE_DURATION)) flags |= AFLAG_DURATION; - data << uint8(flags); + data << uint16(flags); data << uint8(aura->GetCasterLevel()); // send stack amount for aura which could be stacked (never 0 - causes incorrect display) or charges // stack amount has priority over charges (checked on retail with spell 50262) @@ -206,6 +209,12 @@ void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const data << uint32(aura->GetMaxDuration()); data << uint32(aura->GetDuration()); } + + if (flags & AFLAG_ANY_EFFECT_AMOUNT_SENT) + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (AuraEffect const* eff = aura->GetEffect(i)) + if (HasEffect(i)) // Not all of aura's effects have to be applied on every target + data << int32(eff->GetAmount()); } void AuraApplication::ClientUpdate(bool remove) @@ -337,7 +346,7 @@ m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false) { - if (m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) + if (m_spellInfo->ManaPerSecond) m_timeCla = 1 * IN_MILLISECONDS; m_maxDuration = CalcMaxDuration(caster); @@ -684,7 +693,7 @@ void Aura::Update(uint32 diff, Unit* caster) m_timeCla -= diff; else if (caster) { - if (int32 manaPerSecond = m_spellInfo->ManaPerSecond + m_spellInfo->ManaPerSecondPerLevel * caster->getLevel()) + if (int32 manaPerSecond = m_spellInfo->ManaPerSecond) { m_timeCla += 1000 - diff; @@ -755,18 +764,35 @@ void Aura::RefreshDuration(bool withMods) else SetDuration(GetMaxDuration()); - if (m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) + if (m_spellInfo->ManaPerSecond) m_timeCla = 1 * IN_MILLISECONDS; } void Aura::RefreshTimers() { m_maxDuration = CalcMaxDuration(); + bool resetPeriodic = true; + if (m_spellInfo->AttributesEx8 & SPELL_ATTR8_DONT_RESET_PERIODIC_TIMER) + { + int32 minAmplitude = m_maxDuration; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (AuraEffect const* eff = GetEffect(i)) + if (int32 ampl = eff->GetAmplitude()) + minAmplitude = std::min(ampl, minAmplitude); + + // If only one tick remaining, roll it over into new duration + if (GetDuration() <= minAmplitude) + { + m_maxDuration += GetDuration(); + resetPeriodic = false; + } + } + RefreshDuration(); Unit* caster = GetCaster(); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (HasEffect(i)) - GetEffect(i)->CalculatePeriodic(caster, false, false); + GetEffect(i)->CalculatePeriodic(caster, resetPeriodic, false); } void Aura::SetCharges(uint8 charges) @@ -789,7 +815,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const if (Player* modOwner = caster->GetSpellModOwner()) modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges); - return maxProcCharges; + return uint8(maxProcCharges); } bool Aura::ModCharges(int32 num, AuraRemoveMode removeMode) @@ -952,9 +978,12 @@ bool Aura::CanBeSaved() const case 40075: // Fel Flak Fire case 55849: // Power Spark return false; - break; } + // When a druid logins, he doesnt have either eclipse power, nor the marker auras, nor the eclipse buffs. Dont save them. + if (GetId() == 67483 || GetId() == 67484 || GetId() == 48517 || GetId() == 48518) + return false; + // don't save auras removed by proc system if (IsUsingCharges() && !GetCharges()) return false; @@ -964,7 +993,7 @@ bool Aura::CanBeSaved() const bool Aura::CanBeSentToClient() const { - return !IsPassive() || GetSpellInfo()->HasAreaAuraEffect() || HasEffectType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); + return !IsPassive() || GetSpellInfo()->HasAreaAuraEffect() || HasEffectType(SPELL_AURA_ABILITY_IGNORE_AURASTATE) || HasEffectType(SPELL_AURA_CAST_WHILE_WALKING); } bool Aura::IsSingleTargetWith(Aura const* aura) const @@ -1208,20 +1237,8 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b case SPELLFAMILY_MAGE: if (!caster) break; - if (GetSpellInfo()->SpellFamilyFlags[0] & 0x00000001 && GetSpellInfo()->SpellFamilyFlags[2] & 0x00000008) - { - // Glyph of Fireball - if (caster->HasAura(56368)) - SetDuration(0); - } - else if (GetSpellInfo()->SpellFamilyFlags[0] & 0x00000020 && GetSpellInfo()->SpellVisual[0] == 13) - { - // Glyph of Frostbolt - if (caster->HasAura(56370)) - SetDuration(0); - } /// @todo This should be moved to similar function in spell::hit - else if (GetSpellInfo()->SpellFamilyFlags[0] & 0x01000000) + if (GetSpellInfo()->SpellFamilyFlags[0] & 0x01000000) { // Polymorph Sound - Sheep && Penguin if (GetSpellInfo()->SpellIconID == 82 && GetSpellInfo()->SpellVisual[0] == 12978) @@ -1253,18 +1270,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b caster->CastSpell(caster, spellId, true); } break; - case 44544: // Fingers of Frost - { - // See if we already have the indicator aura. If not, create one. - if (Aura* aur = target->GetAura(74396)) - { - // Aura already there. Refresh duration and set original charges - aur->SetCharges(2); - aur->RefreshDuration(); - } - else - target->AddAura(74396, target); - } default: break; } @@ -1276,7 +1281,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b if (GetSpellInfo()->SpellFamilyFlags[0] & 0x02000000 && GetEffect(0)) { // Improved Devouring Plague - if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 1)) + if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 0)) { uint32 damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), GetEffect(0)->GetAmount(), DOT); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT); @@ -1306,49 +1311,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b if (target->HasAura(58039)) // Glyph of Blurred Speed target->CastSpell(target, 61922, true); // Sprint (waterwalk) break; - case SPELLFAMILY_DEATHKNIGHT: - if (!caster) - break; - // Frost Fever and Blood Plague - if (GetSpellInfo()->SpellFamilyFlags[2] & 0x2) - { - // Can't proc on self - if (GetCasterGUID() == target->GetGUID()) - break; - - AuraEffect* aurEff = NULL; - // Ebon Plaguebringer / Crypt Fever - Unit::AuraEffectList const& TalentAuras = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for (Unit::AuraEffectList::const_iterator itr = TalentAuras.begin(); itr != TalentAuras.end(); ++itr) - { - if ((*itr)->GetMiscValue() == 7282) - { - aurEff = *itr; - // Ebon Plaguebringer - end search if found - if ((*itr)->GetSpellInfo()->SpellIconID == 1766) - break; - } - } - if (aurEff) - { - uint32 spellId = 0; - switch (aurEff->GetId()) - { - // Ebon Plague - case 51161: spellId = 51735; break; - case 51160: spellId = 51734; break; - case 51099: spellId = 51726; break; - // Crypt Fever - case 49632: spellId = 50510; break; - case 49631: spellId = 50509; break; - case 49032: spellId = 50508; break; - default: - TC_LOG_ERROR("spells", "Aura::HandleAuraSpecificMods: Unknown rank of Crypt Fever/Ebon Plague (%d) found", aurEff->GetId()); - } - caster->CastSpell(target, spellId, true, 0, GetEffect(0)); - } - } - break; } } // mods at aura remove @@ -1377,54 +1339,9 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b target->CastSpell(target, 32612, true, NULL, GetEffect(1)); target->CombatStop(); break; - case 74396: // Fingers of Frost - // Remove the IGNORE_AURASTATE aura - target->RemoveAurasDueToSpell(44544); - break; - case 44401: //Missile Barrage - case 48108: //Hot Streak - case 57761: //Fireball! - if (removeMode != AURA_REMOVE_BY_EXPIRE || aurApp->GetBase()->IsExpired()) - break; - if (target->HasAura(70752)) //Item - Mage T10 2P Bonus - target->CastSpell(target, 70753, true); - break; default: break; } - if (!caster) - break; - // Ice barrier - dispel/absorb remove - if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && GetSpellInfo()->SpellFamilyFlags[1] & 0x1) - { - // Shattered Barrier - if (AuraEffect* dummy = caster->GetDummyAuraEffect(SPELLFAMILY_MAGE, 2945, 0)) - if (roll_chance_i(dummy->GetSpellInfo()->ProcChance)) - caster->CastSpell(target, 55080, true, NULL, GetEffect(0)); - } - break; - case SPELLFAMILY_WARRIOR: - if (!caster) - break; - // Spell Reflection - if (GetSpellInfo()->SpellFamilyFlags[1] & 0x2) - { - if (removeMode != AURA_REMOVE_BY_DEFAULT) - { - // Improved Spell Reflection - if (caster->GetDummyAuraEffect(SPELLFAMILY_WARRIOR, 1935, 1)) - { - // aura remove - remove auras from all party members - std::list<Unit*> PartyMembers; - target->GetPartyMembers(PartyMembers); - for (std::list<Unit*>::iterator itr = PartyMembers.begin(); itr != PartyMembers.end(); ++itr) - { - if ((*itr)!= target) - (*itr)->RemoveAurasWithFamily(SPELLFAMILY_WARRIOR, 0, 0x2, 0, GetCasterGUID()); - } - } - } - } break; case SPELLFAMILY_WARLOCK: if (!caster) @@ -1450,18 +1367,8 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b case SPELLFAMILY_PRIEST: if (!caster) break; - // Shadow word: Pain // Vampiric Touch - if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && (GetSpellInfo()->SpellFamilyFlags[0] & 0x00008000 || GetSpellInfo()->SpellFamilyFlags[1] & 0x00000400)) - { - // Shadow Affinity - if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 178, 1)) - { - int32 basepoints0 = aurEff->GetAmount() * caster->GetCreateMana() / 100; - caster->CastCustomSpell(caster, 64103, &basepoints0, NULL, NULL, true, NULL, GetEffect(0)); - } - } // Power word: shield - else if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && GetSpellInfo()->SpellFamilyFlags[0] & 0x00000001) + if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && GetSpellInfo()->SpellFamilyFlags[0] & 0x00000001) { // Rapture if (Aura const* aura = caster->GetAuraOfRankedSpell(47535)) @@ -1483,65 +1390,12 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b // effect on caster if (AuraEffect const* aurEff = aura->GetEffect(0)) { - float multiplier = (float)aurEff->GetAmount(); - if (aurEff->GetId() == 47535) - multiplier -= 0.5f; - else if (aurEff->GetId() == 47537) - multiplier += 0.5f; - + float multiplier = float(aurEff->GetAmount()); int32 basepoints0 = int32(CalculatePct(caster->GetMaxPower(POWER_MANA), multiplier)); caster->CastCustomSpell(caster, 47755, &basepoints0, NULL, NULL, true); } - // effect on aura target - if (AuraEffect const* aurEff = aura->GetEffect(1)) - { - if (!roll_chance_i(aurEff->GetAmount())) - break; - - int32 triggeredSpellId = 0; - switch (target->getPowerType()) - { - case POWER_MANA: - { - int32 basepoints0 = int32(CalculatePct(target->GetMaxPower(POWER_MANA), 2)); - caster->CastCustomSpell(target, 63654, &basepoints0, NULL, NULL, true); - break; - } - case POWER_RAGE: triggeredSpellId = 63653; break; - case POWER_ENERGY: triggeredSpellId = 63655; break; - case POWER_RUNIC_POWER: triggeredSpellId = 63652; break; - default: - break; - } - if (triggeredSpellId) - caster->CastSpell(target, triggeredSpellId, true); - } } } - switch (GetId()) - { - case 47788: // Guardian Spirit - if (removeMode != AURA_REMOVE_BY_EXPIRE) - break; - if (caster->GetTypeId() != TYPEID_PLAYER) - break; - - Player* player = caster->ToPlayer(); - // Glyph of Guardian Spirit - if (AuraEffect* aurEff = player->GetAuraEffect(63231, 0)) - { - if (!player->HasSpellCooldown(47788)) - break; - - player->RemoveSpellCooldown(GetSpellInfo()->Id, true); - player->AddSpellCooldown(GetSpellInfo()->Id, 0, uint32(time(NULL) + aurEff->GetAmount())); - - WorldPacket data; - player->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, GetSpellInfo()->Id, aurEff->GetAmount()*IN_MILLISECONDS); - player->SendDirectMessage(&data); - } - break; - } break; case SPELLFAMILY_ROGUE: // Remove Vanish on stealth remove @@ -1592,32 +1446,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b break; } break; - case SPELLFAMILY_ROGUE: - // Stealth - if (GetSpellInfo()->SpellFamilyFlags[0] & 0x00400000) - { - // Master of subtlety - if (AuraEffect const* aurEff = target->GetAuraEffectOfRankedSpell(31221, 0)) - { - if (!apply) - target->CastSpell(target, 31666, true); - else - { - int32 basepoints0 = aurEff->GetAmount(); - target->CastCustomSpell(target, 31665, &basepoints0, NULL, NULL, true); - } - } - // Overkill - if (target->HasAura(58426)) - { - if (!apply) - target->CastSpell(target, 58428, true); - else - target->CastSpell(target, 58427, true); - } - break; - } - break; case SPELLFAMILY_HUNTER: switch (GetId()) { @@ -1640,7 +1468,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b case SPELLFAMILY_PALADIN: switch (GetId()) { - case 31842: // Divine Illumination + case 31842: // Divine Favor // Item - Paladin T10 Holy 2P Bonus if (target->HasAura(70755)) { @@ -2537,4 +2365,3 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* /*caster* } } } - diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 10339a6ac3a..bf518859b49 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -34,6 +34,7 @@ #include "Totem.h" #include "Spell.h" #include "DynamicObject.h" +#include "Guild.h" #include "Group.h" #include "UpdateData.h" #include "MapManager.h" @@ -53,6 +54,7 @@ #include "SpellScript.h" #include "InstanceScript.h" #include "SpellInfo.h" +#include "DB2Stores.h" #include "Battlefield.h" #include "BattlefieldMgr.h" @@ -548,7 +550,7 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme // wand case if ((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId() == TYPEID_PLAYER) if (Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK)) - m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->Damage[0].DamageType); + m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->DamageType); if (originalCasterGUID) m_originalCasterGUID = originalCasterGUID; @@ -824,7 +826,10 @@ void Spell::SelectSpellTargets() else if (m_spellInfo->Speed > 0.0f) { float dist = m_caster->GetDistance(*m_targets.GetDstPos()); - m_delayMoment = (uint64) floor(dist / m_spellInfo->Speed * 1000.0f); + if (!(m_spellInfo->AttributesEx9 & SPELL_ATTR9_SPECIAL_DELAY_CALCULATION)) + m_delayMoment = uint64(floor(dist / m_spellInfo->Speed * 1000.0f)); + else + m_delayMoment = uint64(m_spellInfo->Speed * 1000.0f); } } } @@ -1114,14 +1119,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge { // Other special target selection goes here if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) - { - Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); - for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j) - if ((*j)->IsAffectedOnSpell(m_spellInfo)) - maxTargets += (*j)->GetAmount(); - Trinity::Containers::RandomResizeList(targets, maxTargets); - } for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) { @@ -1164,6 +1162,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge ASSERT(false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type"); return; } + if (!referer) return; @@ -1185,6 +1184,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge ASSERT(false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type"); return; } + std::list<WorldObject*> targets; float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod; SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions); @@ -1195,14 +1195,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge { // Other special target selection goes here if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) - { - Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); - for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j) - if ((*j)->IsAffectedOnSpell(m_spellInfo)) - maxTargets += (*j)->GetAmount(); - Trinity::Containers::RandomResizeList(targets, maxTargets); - } for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) { @@ -1633,6 +1626,9 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex) CallScriptDestinationTargetSelectHandlers(dest, effIndex, SpellImplicitTargetInfo(TARGET_DEST_TRAJ)); m_targets.ModDst(dest); } + + if (Vehicle* veh = m_caster->GetVehicleKit()) + veh->SetLastShootPos(*m_targets.GetDstPos()); } void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) @@ -1964,8 +1960,9 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/) (m_spellInfo->SpellFamilyFlags[0] & 0x18 || // Freezing and Frost Trap, Freezing Arrow m_spellInfo->Id == 57879 || // Snake Trap - done this way to avoid double proc m_spellInfo->SpellFamilyFlags[2] & 0x00024000)) // Explosive and Immolation Trap - + { m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION; + } /* Effects which are result of aura proc from triggered spell cannot proc to prevent chain proc of these spells */ @@ -2076,7 +2073,11 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= if (dist < 5.0f) dist = 5.0f; - targetInfo.timeDelay = (uint64) floor(dist / m_spellInfo->Speed * 1000.0f); + + if (!(m_spellInfo->AttributesEx9 & SPELL_ATTR9_SPECIAL_DELAY_CALCULATION)) + targetInfo.timeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f)); + else + targetInfo.timeDelay = uint64(m_spellInfo->Speed * 1000.0f); // Calculate minimum incoming time if (m_delayMoment == 0 || m_delayMoment > targetInfo.timeDelay) @@ -2155,7 +2156,12 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask) float dist = m_caster->GetDistance(go->GetPositionX(), go->GetPositionY(), go->GetPositionZ()); if (dist < 5.0f) dist = 5.0f; - target.timeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f)); + + if (!(m_spellInfo->AttributesEx9 & SPELL_ATTR9_SPECIAL_DELAY_CALCULATION)) + target.timeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f)); + else + target.timeDelay = uint64(m_spellInfo->Speed * 1000.0f); + if (m_delayMoment == 0 || m_delayMoment > target.timeDelay) m_delayMoment = target.timeDelay; } @@ -2456,25 +2462,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA // disable effects to which unit is immune SpellMissInfo returnVal = SPELL_MISS_IMMUNE; for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - { if (effectMask & (1 << effectNumber)) - { if (unit->IsImmunedToSpellEffect(m_spellInfo, effectNumber)) effectMask &= ~(1 << effectNumber); - else if (m_spellInfo->Effects[effectNumber].IsAura() && !m_spellInfo->IsPositiveEffect(effectNumber)) - { - int32 debuff_resist_chance = unit->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(m_spellInfo->Dispel)); - debuff_resist_chance += unit->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(m_spellInfo->Dispel)); - - if (debuff_resist_chance > 0) - if (irand(0, 10000) <= (debuff_resist_chance * 100)) - { - effectMask &= ~(1 << effectNumber); - returnVal = SPELL_MISS_RESIST; - } - } - } - } if (!effectMask) return returnVal; @@ -2485,14 +2475,14 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA if (Player* player = unit->ToPlayer()) { player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, m_spellInfo->Id); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id, 0, m_caster); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id, 0, 0, m_caster); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, m_spellInfo->Id); } if (Player* player = m_caster->ToPlayer()) { player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER, m_spellInfo->Id); - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, unit); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, 0, unit); } if (m_caster != unit) @@ -2612,12 +2602,25 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA duration = m_originalCaster->ModSpellDuration(aurSpellInfo, unit, duration, positive, effectMask); - // Haste modifies duration of channeled spells - if (m_spellInfo->IsChanneled()) - m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this); - // and duration of auras affected by SPELL_AURA_PERIODIC_HASTE - else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, aurSpellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) - duration = int32(duration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED)); + if (duration > 0) + { + // Haste modifies duration of channeled spells + if (m_spellInfo->IsChanneled()) + m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this); + else if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) + { + int32 origDuration = duration; + duration = 0; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (AuraEffect const* eff = m_spellAura->GetEffect(i)) + if (int32 amplitude = eff->GetAmplitude()) // amplitude is hastened by UNIT_MOD_CAST_SPEED + duration = std::max(std::max(origDuration / amplitude, 1) * amplitude, duration); + + // if there is no periodic effect + if (!duration) + duration = int32(origDuration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED)); + } + } if (duration != m_spellAura->GetMaxDuration()) { @@ -2673,7 +2676,7 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask) { if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance)) { - m_caster->CastSpell(unit, i->triggeredSpell, true); + m_caster->CastSpell(unit, i->triggeredSpell, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_TARGET_CHECK)); TC_LOG_DEBUG("spells", "Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->triggeredSpell->Id); // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration @@ -2882,6 +2885,10 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered m_needComboPoints = false; SpellCastResult result = CheckCast(true); + // target is checked in too many locations and with different results to handle each of them + // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks + if (_triggeredCastFlags & TRIGGERED_IGNORE_TARGET_CHECK && result == SPELL_FAILED_BAD_TARGETS) + result = SPELL_CAST_OK; if (result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering { // Periodic auras should be interrupted when aura triggers a spell which can't be cast @@ -2909,18 +2916,20 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered { player->SetSpellModTakingSpell(this, true); // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail) - m_casttime = m_spellInfo->CalcCastTime(this); + m_casttime = m_spellInfo->CalcCastTime(player->getLevel(), this); player->SetSpellModTakingSpell(this, false); } else m_casttime = 0; // Set cast time to 0 if .cheat casttime is enabled. } else - m_casttime = m_spellInfo->CalcCastTime(this); + m_casttime = m_spellInfo->CalcCastTime(m_caster->getLevel(), this); // don't allow channeled spells / spells with cast time to be cast while moving // (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in) - if ((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->isMoving() && m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) + // don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect + if (((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->isMoving() && + m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo)) { SendCastResult(SPELL_FAILED_MOVING); finish(false); @@ -3273,7 +3282,7 @@ void Spell::handle_immediate() // Remove used for cast item if need (it can be already NULL after TakeReagents call TakeCastItem(); - // handle ammo consumption for Hunter's volley spell + // handle ammo consumption for thrown weapons if (m_spellInfo->IsRangedWeaponSpell() && m_spellInfo->IsChanneled()) TakeAmmo(); @@ -3408,6 +3417,9 @@ void Spell::_handle_finish_phase() // Real add combo points from effects if (m_comboPointGain) m_caster->m_movedPlayer->GainSpellComboPoints(m_comboPointGain); + + if (m_spellInfo->PowerType == POWER_HOLY_POWER && m_caster->m_movedPlayer->getClass() == CLASS_PALADIN) + HandleHolyPower(m_caster->m_movedPlayer); } if (m_caster->m_extraAttacks && GetSpellInfo()->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) @@ -3455,9 +3467,11 @@ void Spell::update(uint32 difftime) } // check if the player caster has moved before the spell finished + // with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) && m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) && - (m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR))) + (m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) && + !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo)) { // don't cancel for melee, autorepeat, triggered and instant spells if (!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered()) @@ -3564,7 +3578,7 @@ void Spell::finish(bool ok) Unit::AuraEffectList const& vIgnoreReset = m_caster->GetAuraEffectsByType(SPELL_AURA_IGNORE_MELEE_RESET); for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i) { - if ((*i)->IsAffectedOnSpell(m_spellInfo)) + if ((*i)->IsAffectingSpell(m_spellInfo)) { found = true; break; @@ -3600,13 +3614,46 @@ void Spell::finish(bool ok) m_caster->AttackStop(); } -void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError) +void Spell::SendCastResult(SpellCastResult result) +{ + if (result == SPELL_CAST_OK) + return; + + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time + return; + + SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError); +} + +void Spell::SendPetCastResult(SpellCastResult result) { - data << uint8(castCount); // single cast or multi 2.3 (0/1) + if (result == SPELL_CAST_OK) + return; + + Unit* owner = m_caster->GetCharmerOrOwner(); + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + return; + + SendCastResult(owner->ToPlayer(), m_spellInfo, m_cast_count, result, SPELL_CUSTOM_ERROR_NONE, SMSG_PET_CAST_FAILED); +} + +void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, Opcodes opcode /*= SMSG_CAST_FAILED*/) +{ + if (result == SPELL_CAST_OK) + return; + + WorldPacket data(opcode, (4+1+1)); + data << uint8(cast_count); data << uint32(spellInfo->Id); data << uint8(result); // problem switch (result) { + case SPELL_FAILED_NOT_READY: + data << uint32(0); // unknown (value 1 update cooldowns on client flag) + break; case SPELL_FAILED_REQUIRES_SPELL_FOCUS: data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id break; @@ -3659,9 +3706,29 @@ void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo con data << uint32(proto->ItemLimitCategory); break; } + case SPELL_FAILED_PREVENTED_BY_MECHANIC: + data << uint32(spellInfo->GetAllEffectsMechanicMask()); // SpellMechanic.dbc id + break; + case SPELL_FAILED_NEED_EXOTIC_AMMO: + data << uint32(spellInfo->EquippedItemSubClassMask); // seems correct... + break; + case SPELL_FAILED_NEED_MORE_ITEMS: + data << uint32(0); // Item id + data << uint32(0); // Item count? + break; + case SPELL_FAILED_MIN_SKILL: + data << uint32(0); // SkillLine.dbc id + data << uint32(0); // required skill value + break; + case SPELL_FAILED_FISHING_TOO_LOW: + data << uint32(0); // required fishing skill + break; case SPELL_FAILED_CUSTOM_ERROR: data << uint32(customError); break; + case SPELL_FAILED_SILENCED: + data << uint32(0); // Unknown + break; case SPELL_FAILED_REAGENTS: { uint32 missingItem = 0; @@ -3683,72 +3750,13 @@ void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo con data << uint32(missingItem); // first missing item break; } - case SPELL_FAILED_PREVENTED_BY_MECHANIC: - data << uint32(spellInfo->Mechanic); - break; - case SPELL_FAILED_NEED_EXOTIC_AMMO: - data << uint32(spellInfo->EquippedItemSubClassMask); - break; - case SPELL_FAILED_NEED_MORE_ITEMS: - data << uint32(0); // Item entry - data << uint32(0); // Count - break; - case SPELL_FAILED_MIN_SKILL: - data << uint32(0); // SkillLine.dbc Id - data << uint32(0); // Amount - break; - case SPELL_FAILED_FISHING_TOO_LOW: - data << uint32(0); // Skill level - break; + // TODO: SPELL_FAILED_NOT_STANDING default: break; } -} - -void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/) -{ - if (result == SPELL_CAST_OK) - return; - - WorldPacket data(SMSG_CAST_FAILED, 1 + 4 + 1); - WriteCastResultInfo(data, caster, spellInfo, castCount, result, customError); - caster->GetSession()->SendPacket(&data); } -void Spell::SendCastResult(SpellCastResult result) -{ - if (result == SPELL_CAST_OK) - return; - - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time - return; - - SendCastResult(m_caster->ToPlayer(), m_spellInfo, m_cast_count, result, m_customError); -} - -void Spell::SendPetCastResult(SpellCastResult result) -{ - if (result == SPELL_CAST_OK) - return; - - Unit* owner = m_caster->GetCharmerOrOwner(); - if (!owner) - return; - - Player* player = owner->ToPlayer(); - if (!player) - return; - - WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1); - WriteCastResultInfo(data, player, m_spellInfo, m_cast_count, result, m_customError); - - player->GetSession()->SendPacket(&data); -} - void Spell::SendSpellStart() { if (!IsNeedSendToClient()) @@ -3756,19 +3764,17 @@ void Spell::SendSpellStart() //TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id); - uint32 castFlags = CAST_FLAG_UNKNOWN_2; + uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY; if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell) castFlags |= CAST_FLAG_PENDING; - if (m_spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO) - castFlags |= CAST_FLAG_AMMO; if ((m_caster->GetTypeId() == TYPEID_PLAYER || (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet())) && m_spellInfo->PowerType != POWER_HEALTH) castFlags |= CAST_FLAG_POWER_LEFT_SELF; - if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNE) + if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNES) castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); @@ -3781,22 +3787,58 @@ void Spell::SendSpellStart() data << uint8(m_cast_count); // pending spell cast? data << uint32(m_spellInfo->Id); // spellId data << uint32(castFlags); // cast flags - data << int32(m_timer); // delay? + data << uint32(m_timer); // delay? + data << uint32(m_casttime); m_targets.Write(data); if (castFlags & CAST_FLAG_POWER_LEFT_SELF) data << uint32(m_caster->GetPower((Powers)m_spellInfo->PowerType)); - if (castFlags & CAST_FLAG_AMMO) - WriteAmmoToPacket(&data); + if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list + { + //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature + //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster + if (Player* player = m_caster->ToPlayer()) + { + data << uint8(m_runesState); // runes state before + data << uint8(player->GetRunesState()); // runes state after + for (uint8 i = 0; i < MAX_RUNES; ++i) + { + // float casts ensure the division is performed on floats as we need float result + float baseCd = float(player->GetRuneBaseCooldown(i)); + data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed + } + } + else + { + data << uint8(0); + data << uint8(0); + for (uint8 i = 0; i < MAX_RUNES; ++i) + data << uint8(0); + } + } - if (castFlags & CAST_FLAG_UNKNOWN_23) + if (castFlags & CAST_FLAG_PROJECTILE) + { + data << uint32(0); // Ammo display ID + data << uint32(0); // Inventory Type + } + + if (castFlags & CAST_FLAG_IMMUNITY) { data << uint32(0); data << uint32(0); } + if (castFlags & CAST_FLAG_HEAL_PREDICTION) + { + data << uint32(0); + data << uint8(0); // unkByte + // if (unkByte == 2) + // data.append(0); + } + m_caster->SendMessageToSet(&data, true); } @@ -3814,9 +3856,6 @@ void Spell::SendSpellGo() if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell) castFlags |= CAST_FLAG_PENDING; - if (m_spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO) - castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual - if ((m_caster->GetTypeId() == TYPEID_PLAYER || (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet())) && m_spellInfo->PowerType != POWER_HEALTH) @@ -3825,7 +3864,7 @@ void Spell::SendSpellGo() if ((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->getClass() == CLASS_DEATH_KNIGHT) && m_spellInfo->RuneCostID - && m_spellInfo->PowerType == POWER_RUNE + && m_spellInfo->PowerType == POWER_RUNES && !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)) { castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it @@ -3852,6 +3891,7 @@ void Spell::SendSpellGo() data << uint8(m_cast_count); // pending spell cast? data << uint32(m_spellInfo->Id); // spellId data << uint32(castFlags); // cast flags + data << uint32(m_timer); data << uint32(getMSTime()); // timestamp WriteSpellGoTargets(&data); @@ -3867,30 +3907,28 @@ void Spell::SendSpellGo() //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster if (Player* player = m_caster->ToPlayer()) { - uint8 runeMaskInitial = m_runesState; - uint8 runeMaskAfterCast = player->GetRunesState(); - data << uint8(runeMaskInitial); // runes state before - data << uint8(runeMaskAfterCast); // runes state after + data << uint8(m_runesState); // runes state before + data << uint8(player->GetRunesState()); // runes state after for (uint8 i = 0; i < MAX_RUNES; ++i) { - uint8 mask = (1 << i); - if (mask & runeMaskInitial && !(mask & runeMaskAfterCast)) // usable before andon cooldown now... - { - // float casts ensure the division is performed on floats as we need float result - float baseCd = float(player->GetRuneBaseCooldown(i)); - data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed - } + // float casts ensure the division is performed on floats as we need float result + float baseCd = float(player->GetRuneBaseCooldown(i)); + data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed } } } + if (castFlags & CAST_FLAG_ADJUST_MISSILE) { data << m_targets.GetElevation(); data << uint32(m_delayMoment); } - if (castFlags & CAST_FLAG_AMMO) - WriteAmmoToPacket(&data); + if (castFlags & CAST_FLAG_PROJECTILE) + { + data << uint32(0); // Ammo display ID + data << uint32(0); // Inventory Type + } if (castFlags & CAST_FLAG_VISUAL_CHAIN) { @@ -3903,79 +3941,21 @@ void Spell::SendSpellGo() data << uint8(0); } - m_caster->SendMessageToSet(&data, true); -} - -void Spell::WriteAmmoToPacket(WorldPacket* data) -{ - uint32 ammoInventoryType = 0; - uint32 ammoDisplayID = 0; - - if (m_caster->GetTypeId() == TYPEID_PLAYER) + if (m_targets.GetTargetMask() & TARGET_FLAG_EXTRA_TARGETS) { - Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK); - if (pItem) + data << uint32(0); // Extra targets count + /* + for (uint8 i = 0; i < count; ++i) { - ammoInventoryType = pItem->GetTemplate()->InventoryType; - if (ammoInventoryType == INVTYPE_THROWN) - ammoDisplayID = pItem->GetTemplate()->DisplayInfoID; - else - { - uint32 ammoID = m_caster->ToPlayer()->GetUInt32Value(PLAYER_AMMO_ID); - if (ammoID) - { - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(ammoID); - if (pProto) - { - ammoDisplayID = pProto->DisplayInfoID; - ammoInventoryType = pProto->InventoryType; - } - } - else if (m_caster->HasAura(46699)) // Requires No Ammo - { - ammoDisplayID = 5996; // normal arrow - ammoInventoryType = INVTYPE_AMMO; - } - } - } - } - else - { - for (uint8 i = 0; i < 3; ++i) - { - if (uint32 item_id = m_caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i)) - { - if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id)) - { - if (itemEntry->Class == ITEM_CLASS_WEAPON) - { - switch (itemEntry->SubClass) - { - case ITEM_SUBCLASS_WEAPON_THROWN: - ammoDisplayID = itemEntry->DisplayId; - ammoInventoryType = itemEntry->InventoryType; - break; - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - ammoDisplayID = 5996; // is this need fixing? - ammoInventoryType = INVTYPE_AMMO; - break; - case ITEM_SUBCLASS_WEAPON_GUN: - ammoDisplayID = 5998; // is this need fixing? - ammoInventoryType = INVTYPE_AMMO; - break; - } - - if (ammoDisplayID) - break; - } - } - } + data << float(0); // Target Position X + data << float(0); // Target Position Y + data << float(0); // Target Position Z + data << uint64(0); // Target Guid } + */ } - *data << uint32(ammoDisplayID); - *data << uint32(ammoInventoryType); + m_caster->SendMessageToSet(&data, true); } /// Writes miss and hit targets for a SMSG_SPELL_GO packet @@ -4087,11 +4067,49 @@ void Spell::ExecuteLogEffectExtraAttacks(uint8 effIndex, Unit* victim, uint32 at *m_effectExecuteData[effIndex] << uint32(attCount); } -void Spell::ExecuteLogEffectInterruptCast(uint8 effIndex, Unit* victim, uint32 spellId) -{ - InitEffectExecuteData(effIndex); - m_effectExecuteData[effIndex]->append(victim->GetPackGUID()); - *m_effectExecuteData[effIndex] << uint32(spellId); +void Spell::ExecuteLogEffectInterruptCast(uint8 /*effIndex*/, Unit* victim, uint32 spellId) +{ + ObjectGuid casterGuid = m_caster->GetGUID(); + ObjectGuid targetGuid = victim->GetGUID(); + + WorldPacket data(SMSG_SPELLINTERRUPTLOG, 8 + 8 + 4 + 4); + data.WriteBit(targetGuid[4]); + data.WriteBit(casterGuid[5]); + data.WriteBit(casterGuid[6]); + data.WriteBit(casterGuid[1]); + data.WriteBit(casterGuid[3]); + data.WriteBit(casterGuid[0]); + data.WriteBit(targetGuid[3]); + data.WriteBit(targetGuid[5]); + data.WriteBit(targetGuid[1]); + data.WriteBit(casterGuid[4]); + data.WriteBit(casterGuid[7]); + data.WriteBit(targetGuid[7]); + data.WriteBit(targetGuid[6]); + data.WriteBit(targetGuid[2]); + data.WriteBit(casterGuid[2]); + data.WriteBit(targetGuid[0]); + + data.WriteByteSeq(casterGuid[7]); + data.WriteByteSeq(casterGuid[6]); + data.WriteByteSeq(casterGuid[3]); + data.WriteByteSeq(casterGuid[2]); + data.WriteByteSeq(targetGuid[3]); + data.WriteByteSeq(targetGuid[6]); + data.WriteByteSeq(targetGuid[2]); + data.WriteByteSeq(targetGuid[4]); + data.WriteByteSeq(targetGuid[7]); + data.WriteByteSeq(targetGuid[0]); + data.WriteByteSeq(casterGuid[4]); + data << uint32(m_spellInfo->Id); + data.WriteByteSeq(targetGuid[1]); + data.WriteByteSeq(casterGuid[0]); + data.WriteByteSeq(casterGuid[5]); + data.WriteByteSeq(casterGuid[1]); + data << uint32(spellId); + data.WriteByteSeq(targetGuid[5]); + + m_caster->SendMessageToSet(&data, true); } void Spell::ExecuteLogEffectDurabilityDamage(uint8 effIndex, Unit* victim, int32 itemId, int32 slot) @@ -4181,7 +4199,25 @@ void Spell::SendChannelStart(uint32 duration) data.append(m_caster->GetPackGUID()); data << uint32(m_spellInfo->Id); data << uint32(duration); - + data << uint8(0); // immunity (castflag & 0x04000000) + /* + if (immunity) + { + data << uint32(); // CastSchoolImmunities + data << uint32(); // CastImmunities + } + */ + data << uint8(0); // healPrediction (castflag & 0x40000000) + /* + if (healPrediction) + { + data.appendPackGUID(channelTarget); // target packguid + data << uint32(); // spellid + data << uint8(0); // unk3 + if (unk3 == 2) + data.append(); // unk packed guid (unused ?) + } + */ m_caster->SendMessageToSet(&data, true); m_timer = duration; @@ -4208,8 +4244,8 @@ void Spell::SendResurrectRequest(Player* target) data << uint8(m_caster->GetTypeId() == TYPEID_PLAYER ? 0 : 1); // "you'll be afflicted with resurrection sickness" // override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute - if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_RESURRECTION_TIMER) - data << uint32(0); + // 4.2.2 edit : id of the spell used to resurect. (used client-side for Mass Resurect) + data << uint32(m_spellInfo->Id); target->GetSession()->SendPacket(&data); } @@ -4297,7 +4333,7 @@ void Spell::TakePower() bool hit = true; if (m_caster->GetTypeId() == TYPEID_PLAYER) { - if (powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNE) + if (powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNES) if (uint64 targetGUID = m_targets.GetUnitTargetGUID()) for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) if (ihit->targetGUID == targetGUID) @@ -4313,7 +4349,7 @@ void Spell::TakePower() } } - if (powerType == POWER_RUNE) + if (powerType == POWER_RUNES) { TakeRunePower(hit); return; @@ -4339,10 +4375,6 @@ void Spell::TakePower() m_caster->ModifyPower(powerType, -m_powerCost); else m_caster->ModifyPower(powerType, -irand(0, m_powerCost/4)); - - // Set the five second timer - if (powerType == POWER_MANA && m_powerCost > 0) - m_caster->SetLastManaUse(getMSTime()); } void Spell::TakeAmmo() @@ -4369,14 +4401,12 @@ void Spell::TakeAmmo() m_caster->ToPlayer()->DestroyItemCount(pItem, count, true); } } - else if (uint32 ammo = m_caster->ToPlayer()->GetUInt32Value(PLAYER_AMMO_ID)) - m_caster->ToPlayer()->DestroyItemCount(ammo, 1, true); } } SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) { - if (m_spellInfo->PowerType != POWER_RUNE || !runeCostID) + if (m_spellInfo->PowerType != POWER_RUNES || !runeCostID) return SPELL_CAST_OK; Player* player = m_caster->ToPlayer(); @@ -4585,6 +4615,41 @@ void Spell::HandleThreatSpells() TC_LOG_DEBUG("spells", "Spell %u, added an additional %f threat for %s %u target(s)", m_spellInfo->Id, threat, m_spellInfo->_IsPositiveSpell() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size())); } +void Spell::HandleHolyPower(Player* caster) +{ + if (!caster) + return; + + bool hit = true; + Player* modOwner = caster->GetSpellModOwner(); + + m_powerCost = caster->GetPower(POWER_HOLY_POWER); // Always use all the holy power we have + + if (!m_powerCost || !modOwner) + return; + + if (uint64 targetGUID = m_targets.GetUnitTargetGUID()) + { + for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + { + if (ihit->targetGUID == targetGUID) + { + if (ihit->missCondition != SPELL_MISS_NONE && ihit->missCondition != SPELL_MISS_MISS) + hit = false; + + break; + } + } + + // The spell did hit the target, apply aura cost mods if there are any. + if (hit) + { + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, m_powerCost); + m_caster->ModifyPower(POWER_HOLY_POWER, -m_powerCost); + } + } +} + void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, uint32 i, SpellEffectHandleMode mode) { effectHandleMode = mode; @@ -4597,8 +4662,7 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT TC_LOG_DEBUG("spells", "Spell: %u Effect : %u", m_spellInfo->Id, eff); - // we do not need DamageMultiplier here. - damage = CalculateDamage(i, NULL); + damage = CalculateDamage(i, unitTarget); bool preventDefault = CallScriptEffectHandlers((SpellEffIndex)i, mode); @@ -4670,7 +4734,7 @@ SpellCastResult Spell::CheckCast(bool strict) Unit::AuraEffectList const& ignore = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT); for (Unit::AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) { - if (!(*i)->IsAffectedOnSpell(m_spellInfo)) + if (!(*i)->IsAffectingSpell(m_spellInfo)) continue; checkForm = false; break; @@ -4696,7 +4760,7 @@ SpellCastResult Spell::CheckCast(bool strict) Unit::AuraEffectList const& stateAuras = m_caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); for (Unit::AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j) { - if ((*j)->IsAffectedOnSpell(m_spellInfo)) + if ((*j)->IsAffectingSpell(m_spellInfo)) { m_needComboPoints = false; if ((*j)->GetMiscValue() == 1) @@ -4728,7 +4792,8 @@ SpellCastResult Spell::CheckCast(bool strict) // cancel autorepeat spells if cast start when moving // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code) - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->isMoving()) + // Do not cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->isMoving() && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo)) { // skip stuck spell to allow use it in falling case and apply spell limitations at movement if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK) && @@ -4836,14 +4901,14 @@ SpellCastResult Spell::CheckCast(bool strict) if (!m_caster->ToPlayer()->InBattleground()) return SPELL_FAILED_ONLY_BATTLEGROUNDS; - // do not allow spells to be cast in arenas - // - with greater than 10 min CD without SPELL_ATTR4_USABLE_IN_ARENA flag - // - with SPELL_ATTR4_NOT_USABLE_IN_ARENA flag - if ((m_spellInfo->AttributesEx4 & SPELL_ATTR4_NOT_USABLE_IN_ARENA) || - (m_spellInfo->GetRecoveryTime() > 10 * MINUTE * IN_MILLISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR4_USABLE_IN_ARENA))) - if (MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId())) - if (mapEntry->IsBattleArena()) - return SPELL_FAILED_NOT_IN_ARENA; + // do not allow spells to be cast in arenas or rated battlegrounds + if (Player* player = m_caster->ToPlayer()) + if (player->InArena()/* || player->InRatedBattleGround() NYI*/) + { + SpellCastResult castResult = CheckArenaAndRatedBattlegroundCastRules(); + if (castResult != SPELL_CAST_OK) + return castResult; + } // zone check if (m_caster->GetTypeId() == TYPEID_UNIT || !m_caster->ToPlayer()->IsGameMaster()) @@ -4909,42 +4974,31 @@ SpellCastResult Spell::CheckCast(bool strict) if (castResult != SPELL_CAST_OK) return castResult; - bool hasDispellableAura = false; - bool hasNonDispelEffect = false; - uint32 dispelMask = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DISPEL) - { - if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->AttributesEx & SPELL_ATTR1_MELEE_COMBAT_START) - { - hasDispellableAura = true; - break; - } - - dispelMask |= SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[i].MiscValue)); - } - else if (m_spellInfo->Effects[i].IsEffect()) - { - hasNonDispelEffect = true; - break; - } - - if (!hasNonDispelEffect && !hasDispellableAura && dispelMask && !IsTriggered()) - { - if (Unit* target = m_targets.GetUnitTarget()) - { - DispelChargesList dispelList; - target->GetDispellableAuraList(m_caster, dispelMask, dispelList); - if (dispelList.empty()) - return SPELL_FAILED_NOTHING_TO_DISPEL; - } - } - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { // for effects of spells that have only one target switch (m_spellInfo->Effects[i].Effect) { + case SPELL_EFFECT_DUMMY: + { + if (m_spellInfo->Id == 19938) // Awaken Peon + { + Unit* unit = m_targets.GetUnitTarget(); + if (!unit || !unit->HasAura(17743)) + return SPELL_FAILED_BAD_TARGETS; + } + else if (m_spellInfo->Id == 31789) // Righteous Defense + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return SPELL_FAILED_DONT_REPORT; + + Unit* target = m_targets.GetUnitTarget(); + if (!target || !target->IsFriendlyTo(m_caster) || target->getAttackers().empty()) + return SPELL_FAILED_BAD_TARGETS; + + } + break; + } case SPELL_EFFECT_LEARN_SPELL: { if (m_caster->GetTypeId() != TYPEID_PLAYER) @@ -4968,6 +5022,15 @@ SpellCastResult Spell::CheckCast(bool strict) break; } + case SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB: + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return SPELL_FAILED_BAD_TARGETS; + if (Guild* guild = m_caster->ToPlayer()->GetGuild()) + if (guild->GetLeaderGUID() != m_caster->ToPlayer()->GetGUID()) + return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; + break; + } case SPELL_EFFECT_LEARN_PET_SPELL: { // check target only for unit target case @@ -5526,8 +5589,9 @@ SpellCastResult Spell::CheckCasterAuras() const bool usableInStun = (m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_STUNNED) != 0; // Glyph of Pain Suppression + // Allow Pain Suppression and Guardian Spirit to be cast while stunned // there is no other way to handle it - if (m_spellInfo->Id == 33206 && !m_caster->HasAura(63248)) + if ((m_spellInfo->Id == 33206 || m_spellInfo->Id == 47788) && !m_caster->HasAura(63248)) usableInStun = false; // Check whether the cast should be prevented by any state you might have. @@ -5623,6 +5687,37 @@ SpellCastResult Spell::CheckCasterAuras() const return SPELL_CAST_OK; } +SpellCastResult Spell::CheckArenaAndRatedBattlegroundCastRules() +{ + bool isRatedBattleground = false; // NYI + bool isArena = !isRatedBattleground; + + // check USABLE attributes + // USABLE takes precedence over NOT_USABLE + if (isRatedBattleground && m_spellInfo->AttributesEx9 & SPELL_ATTR9_USABLE_IN_RATED_BATTLEGROUNDS) + return SPELL_CAST_OK; + + if (isArena && m_spellInfo->AttributesEx4 & SPELL_ATTR4_USABLE_IN_ARENA) + return SPELL_CAST_OK; + + // check NOT_USABLE attributes + if (m_spellInfo->AttributesEx4 & SPELL_ATTR4_NOT_USABLE_IN_ARENA_OR_RATED_BG) + return isArena ? SPELL_FAILED_NOT_IN_ARENA : SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND; + + if (isArena && m_spellInfo->AttributesEx9 & SPELL_ATTR9_NOT_USABLE_IN_ARENA) + return SPELL_FAILED_NOT_IN_ARENA; + + // check cooldowns + uint32 spellCooldown = m_spellInfo->GetRecoveryTime(); + if (isArena && spellCooldown > 10 * MINUTE * IN_MILLISECONDS) // not sure if still needed + return SPELL_FAILED_NOT_IN_ARENA; + + if (isRatedBattleground && spellCooldown > 15 * MINUTE * IN_MILLISECONDS) + return SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND; + + return SPELL_CAST_OK; +} + bool Spell::CanAutoCast(Unit* target) { uint64 targetguid = target->GetGUID(); @@ -5743,8 +5838,8 @@ SpellCastResult Spell::CheckPower() return SPELL_FAILED_UNKNOWN; } - //check rune cost only if a spell has PowerType == POWER_RUNE - if (m_spellInfo->PowerType == POWER_RUNE) + //check rune cost only if a spell has PowerType == POWER_RUNES + if (m_spellInfo->PowerType == POWER_RUNES) { SpellCastResult failReason = CheckRuneCost(m_spellInfo->RuneCostID); if (failReason != SPELL_CAST_OK) @@ -5913,25 +6008,7 @@ SpellCastResult Spell::CheckItems() totems -= 1; } if (totems != 0) - return SPELL_FAILED_TOTEMS; //0x7C - - // Check items for TotemCategory (items presence in inventory) - uint32 TotemCategory = 2; - for (uint8 i = 0; i < 2; ++i) - { - if (m_spellInfo->TotemCategory[i] != 0) - { - if (player->HasItemTotemCategory(m_spellInfo->TotemCategory[i])) - { - TotemCategory -= 1; - continue; - } - } - else - TotemCategory -= 1; - } - if (TotemCategory != 0) - return SPELL_FAILED_TOTEM_CATEGORY; //0x7B + return SPELL_FAILED_TOTEMS; } // special checks for spell effects @@ -5971,7 +6048,7 @@ SpellCastResult Spell::CheckItems() } case SPELL_EFFECT_ENCHANT_ITEM: if (m_spellInfo->Effects[i].ItemType && m_targets.GetItemTarget() - && (m_targets.GetItemTarget()->IsWeaponVellum() || m_targets.GetItemTarget()->IsArmorVellum())) + && (m_targets.GetItemTarget()->IsVellum())) { // cannot enchant vellum for other player if (m_targets.GetItemTarget()->GetOwner() != m_caster) @@ -6163,47 +6240,6 @@ SpellCastResult Spell::CheckItems() case ITEM_SUBCLASS_WEAPON_GUN: case ITEM_SUBCLASS_WEAPON_BOW: case ITEM_SUBCLASS_WEAPON_CROSSBOW: - { - uint32 ammo = player->GetUInt32Value(PLAYER_AMMO_ID); - if (!ammo) - { - // Requires No Ammo - if (m_caster->HasAura(46699)) - break; // skip other checks - - return SPELL_FAILED_NO_AMMO; - } - - ItemTemplate const* ammoProto = sObjectMgr->GetItemTemplate(ammo); - if (!ammoProto) - return SPELL_FAILED_NO_AMMO; - - if (ammoProto->Class != ITEM_CLASS_PROJECTILE) - return SPELL_FAILED_NO_AMMO; - - // check ammo ws. weapon compatibility - switch (pItem->GetTemplate()->SubClass) - { - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - if (ammoProto->SubClass != ITEM_SUBCLASS_ARROW) - return SPELL_FAILED_NO_AMMO; - break; - case ITEM_SUBCLASS_WEAPON_GUN: - if (ammoProto->SubClass != ITEM_SUBCLASS_BULLET) - return SPELL_FAILED_NO_AMMO; - break; - default: - return SPELL_FAILED_NO_AMMO; - } - - if (!player->HasItemCount(ammo)) - { - player->SetUInt32Value(PLAYER_AMMO_ID, 0); - return SPELL_FAILED_NO_AMMO; - } - break; - } case ITEM_SUBCLASS_WEAPON_WAND: break; default: @@ -6491,7 +6527,7 @@ bool Spell::IsAutoActionResetSpell() const bool Spell::IsNeedSendToClient() const { return m_spellInfo->SpellVisual[0] || m_spellInfo->SpellVisual[1] || m_spellInfo->IsChanneled() || - m_spellInfo->Speed > 0.0f || (!m_triggeredByAuraSpell && !IsTriggered()); + (m_spellInfo->AttributesEx8 & SPELL_ATTR8_AURA_SEND_AMOUNT) || m_spellInfo->Speed > 0.0f || (!m_triggeredByAuraSpell && !IsTriggered()); } bool Spell::HaveTargetsForEffect(uint8 effect) const @@ -6659,12 +6695,6 @@ void Spell::HandleLaunchPhase() multiplier[i] = m_spellInfo->Effects[i].CalcDamageMultiplier(m_originalCaster, this); bool usesAmmo = (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_DIRECT_DAMAGE) != 0; - Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_CONSUME_NO_AMMO); - for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j) - { - if ((*j)->IsAffectedOnSpell(m_spellInfo)) - usesAmmo=false; - } for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { @@ -7151,7 +7181,7 @@ void Spell::PrepareTriggersExecutedOnHit() Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER); for (Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i) { - if (!(*i)->IsAffectedOnSpell(m_spellInfo)) + if (!(*i)->IsAffectingSpell(m_spellInfo)) continue; SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo(); uint32 auraSpellIdx = (*i)->GetEffIndex(); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 9c4891b95f4..5b976ced426 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -40,11 +40,11 @@ enum SpellCastFlags { CAST_FLAG_NONE = 0x00000000, CAST_FLAG_PENDING = 0x00000001, // aoe combat log? - CAST_FLAG_UNKNOWN_2 = 0x00000002, + CAST_FLAG_HAS_TRAJECTORY = 0x00000002, CAST_FLAG_UNKNOWN_3 = 0x00000004, CAST_FLAG_UNKNOWN_4 = 0x00000008, // ignore AOE visual CAST_FLAG_UNKNOWN_5 = 0x00000010, - CAST_FLAG_AMMO = 0x00000020, // Projectiles visual + CAST_FLAG_PROJECTILE = 0x00000020, CAST_FLAG_UNKNOWN_7 = 0x00000040, CAST_FLAG_UNKNOWN_8 = 0x00000080, CAST_FLAG_UNKNOWN_9 = 0x00000100, @@ -69,7 +69,7 @@ enum SpellCastFlags CAST_FLAG_UNKNOWN_28 = 0x08000000, CAST_FLAG_UNKNOWN_29 = 0x10000000, CAST_FLAG_UNKNOWN_30 = 0x20000000, - CAST_FLAG_UNKNOWN_31 = 0x40000000, + CAST_FLAG_HEAL_PREDICTION = 0x40000000, CAST_FLAG_UNKNOWN_32 = 0x80000000 }; @@ -258,7 +258,7 @@ class Spell void EffectQuestClear(SpellEffIndex effIndex); void EffectTeleUnitsFaceCaster(SpellEffIndex effIndex); void EffectLearnSkill(SpellEffIndex effIndex); - void EffectAddHonor(SpellEffIndex effIndex); + void EffectPlayMovie(SpellEffIndex effIndex); void EffectTradeSkill(SpellEffIndex effIndex); void EffectEnchantItemPerm(SpellEffIndex effIndex); void EffectEnchantItemTmp(SpellEffIndex effIndex); @@ -323,6 +323,7 @@ class Spell void EffectEnergizePct(SpellEffIndex effIndex); void EffectTriggerRitualOfSummoning(SpellEffIndex effIndex); void EffectSummonRaFFriend(SpellEffIndex effIndex); + void EffectUnlockGuildVaultTab(SpellEffIndex effIndex); void EffectKillCreditPersonal(SpellEffIndex effIndex); void EffectKillCredit(SpellEffIndex effIndex); void EffectQuestFail(SpellEffIndex effIndex); @@ -341,8 +342,12 @@ class Spell void EffectActivateSpec(SpellEffIndex effIndex); void EffectPlaySound(SpellEffIndex effIndex); void EffectRemoveAura(SpellEffIndex effIndex); + void EffectDamageFromMaxHealthPCT(SpellEffIndex effIndex); void EffectCastButtons(SpellEffIndex effIndex); void EffectRechargeManaGem(SpellEffIndex effIndex); + void EffectGiveCurrency(SpellEffIndex effIndex); + void EffectResurrectWithAura(SpellEffIndex effIndex); + void EffectCreateAreaTrigger(SpellEffIndex effIndex); typedef std::set<Aura*> UsedSpellMods; @@ -404,6 +409,7 @@ class Spell SpellCastResult CheckPower(); SpellCastResult CheckRuneCost(uint32 runeCostID); SpellCastResult CheckCasterAuras() const; + SpellCastResult CheckArenaAndRatedBattlegroundCastRules(); int32 CalculateDamage(uint8 i, Unit const* target) const { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_spellValue->EffectBasePoints[i]); } @@ -415,15 +421,13 @@ class Spell void DoCreateItem(uint32 i, uint32 itemtype); void WriteSpellGoTargets(WorldPacket* data); - void WriteAmmoToPacket(WorldPacket* data); bool CheckEffectTarget(Unit const* target, uint32 eff) const; bool CanAutoCast(Unit* target); void CheckSrc() { if (!m_targets.HasSrc()) m_targets.SetSrc(*m_caster); } void CheckDst() { if (!m_targets.HasDst()) m_targets.SetDst(*m_caster); } - static void WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError); - static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE); + static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, Opcodes opcode = SMSG_CAST_FAILED); void SendCastResult(SpellCastResult result); void SendPetCastResult(SpellCastResult result); void SendSpellStart(); @@ -445,6 +449,7 @@ class Spell void SendChannelStart(uint32 duration); void SendResurrectRequest(Player* target); + void HandleHolyPower(Player* caster); void HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, uint32 i, SpellEffectHandleMode mode); void HandleThreatSpells(); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 0ee494d2898..7623550d736 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -62,7 +62,10 @@ #include "AccountMgr.h" #include "InstanceScript.h" #include "PathGenerator.h" +#include "Guild.h" +#include "GuildMgr.h" #include "ReputationMgr.h" +#include "AreaTrigger.h" pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= { @@ -111,14 +114,14 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectJumpDest, // 42 SPELL_EFFECT_JUMP_DEST &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP - &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related + &Spell::EffectPlayMovie, // 45 SPELL_EFFECT_PLAY_MOVIE &Spell::EffectUnused, // 46 SPELL_EFFECT_SPAWN clientside, unit appears as if it was just spawned &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused - &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot + &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT unused &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE @@ -229,8 +232,26 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //160 SPELL_EFFECT_160 1 spell - 45534 &Spell::EffectSpecCount, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert) &Spell::EffectActivateSpec, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec - &Spell::EffectNULL, //163 unused + &Spell::EffectUnused, //163 SPELL_EFFECT_163 unused &Spell::EffectRemoveAura, //164 SPELL_EFFECT_REMOVE_AURA + &Spell::EffectDamageFromMaxHealthPCT, //165 SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT + &Spell::EffectGiveCurrency, //166 SPELL_EFFECT_GIVE_CURRENCY + &Spell::EffectNULL, //167 SPELL_EFFECT_167 + &Spell::EffectNULL, //168 SPELL_EFFECT_168 + &Spell::EffectNULL, //169 SPELL_EFFECT_DESTROY_ITEM + &Spell::EffectNULL, //170 SPELL_EFFECT_170 + &Spell::EffectNULL, //171 SPELL_EFFECT_171 + &Spell::EffectResurrectWithAura, //172 SPELL_EFFECT_RESURRECT_WITH_AURA + &Spell::EffectUnlockGuildVaultTab, //173 SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB + &Spell::EffectNULL, //174 SPELL_EFFECT_174 + &Spell::EffectUnused, //175 SPELL_EFFECT_175 unused + &Spell::EffectNULL, //176 SPELL_EFFECT_176 + &Spell::EffectNULL, //177 SPELL_EFFECT_177 + &Spell::EffectUnused, //178 SPELL_EFFECT_178 unused + &Spell::EffectCreateAreaTrigger, //179 SPELL_EFFECT_CREATE_AREATRIGGER + &Spell::EffectUnused, //180 SPELL_EFFECT_180 unused + &Spell::EffectUnused, //181 SPELL_EFFECT_181 unused + &Spell::EffectNULL, //182 SPELL_EFFECT_182 }; void Spell::EffectNULL(SpellEffIndex /*effIndex*/) @@ -259,13 +280,13 @@ void Spell::EffectResurrectNew(SpellEffIndex effIndex) Player* target = unitTarget->ToPlayer(); - if (target->isResurrectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = damage; uint32 mana = m_spellInfo->Effects[effIndex].MiscValue; ExecuteLogEffectResurrect(effIndex, target); - target->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); + target->SetResurrectRequestData(m_caster, health, mana, 0); SendResurrectRequest(target); } @@ -368,15 +389,8 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) } case SPELLFAMILY_WARRIOR: { - // Shield Slam - if (m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->GetCategory() == 1209) - { - uint8 level = m_caster->getLevel(); - uint32 block_value = m_caster->GetShieldBlockValue(uint32(float(level) * 24.5f), uint32(float(level) * 34.5f)); - damage += int32(m_caster->ApplyEffectModifiers(m_spellInfo, effIndex, float(block_value))); - } // Victory Rush - else if (m_spellInfo->SpellFamilyFlags[1] & 0x100) + if (m_spellInfo->Id == 34428) ApplyPct(damage, m_caster->GetTotalAttackPowerValue(BASE_ATTACK)); // Shockwave else if (m_spellInfo->Id == 46968) @@ -393,73 +407,12 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) // Incinerate Rank 1 & 2 if ((m_spellInfo->SpellFamilyFlags[1] & 0x000040) && m_spellInfo->SpellIconID == 2128) { - // Incinerate does more dmg (dmg*0.25) if the target have Immolate debuff. + // Incinerate does more dmg (dmg/6) if the target have Immolate debuff. // Check aura state for speed but aura state set not only for Immolate spell if (unitTarget->HasAuraState(AURA_STATE_CONFLAGRATE)) { if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x4, 0, 0)) - damage += damage/4; - } - } - // Conflagrate - consumes Immolate or Shadowflame - else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE) - { - AuraEffect const* aura = NULL; // found req. aura for damage calculation - - Unit::AuraEffectList const &mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE); - for (Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i) - { - // for caster applied auras only - if ((*i)->GetSpellInfo()->SpellFamilyName != SPELLFAMILY_WARLOCK || - (*i)->GetCasterGUID() != m_caster->GetGUID()) - continue; - - // Immolate - if ((*i)->GetSpellInfo()->SpellFamilyFlags[0] & 0x4) - { - aura = *i; // it selected always if exist - break; - } - - // Shadowflame - if ((*i)->GetSpellInfo()->SpellFamilyFlags[2] & 0x00000002) - aura = *i; // remember but wait possible Immolate as primary priority - } - - // found Immolate or Shadowflame - if (aura) - { - uint32 pdamage = uint32(std::max(aura->GetAmount(), 0)); - pdamage = m_caster->SpellDamageBonusDone(unitTarget, aura->GetSpellInfo(), pdamage, DOT, aura->GetBase()->GetStackAmount()); - pdamage = unitTarget->SpellDamageBonusTaken(m_caster, aura->GetSpellInfo(), pdamage, DOT, aura->GetBase()->GetStackAmount()); - uint32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effIndex + 1)); - uint8 baseTotalTicks = uint8(m_caster->CalcSpellDuration(aura->GetSpellInfo()) / aura->GetSpellInfo()->Effects[EFFECT_0].Amplitude); - damage += int32(CalculatePct(pdamage * baseTotalTicks, pct_dir)); - - uint32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effIndex + 2)) / 3; - m_spellValue->EffectBasePoints[1] = m_spellInfo->Effects[EFFECT_1].CalcBaseValue(int32(CalculatePct(pdamage * baseTotalTicks, pct_dot))); - - apply_direct_bonus = false; - // Glyph of Conflagrate - if (!m_caster->HasAura(56235)) - unitTarget->RemoveAurasDueToSpell(aura->GetId(), m_caster->GetGUID()); - - break; - } - } - // Shadow Bite - else if (m_spellInfo->SpellFamilyFlags[1] & 0x400000) - { - if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet()) - { - if (Player* owner = m_caster->GetOwner()->ToPlayer()) - { - if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, 214, 0)) - { - int32 bp0 = aurEff->GetId() == 54037 ? 4 : 8; - m_caster->CastCustomSpell(m_caster, 54425, &bp0, NULL, NULL, true); - } - } + damage += damage / 6; } } break; @@ -490,20 +443,10 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) // Ferocious Bite if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[0] & 0x000800000) && m_spellInfo->SpellVisual[0] == 6587) { - // converts each extra point of energy into ($f1+$AP/410) additional damage - float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); - float multiple = ap / 410 + m_spellInfo->Effects[effIndex].DamageMultiplier; - int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -30)); - damage += int32(energy * multiple); - damage += int32(CalculatePct(m_caster->ToPlayer()->GetComboPoints() * ap, 7)); - } - // Wrath - else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001) - { - // Improved Insect Swarm - if (AuraEffect const* aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0)) - if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00200000, 0, 0)) - AddPct(damage, aurEff->GetAmount()); + // converts each extra point of energy ( up to 25 energy ) into additional damage + int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -25)); + // 25 energy = 100% more damage + AddPct(damage, energy * 4); } break; } @@ -575,77 +518,6 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) } break; } - case SPELLFAMILY_HUNTER: - { - //Gore - if (m_spellInfo->SpellIconID == 1578) - { - if (m_caster->HasAura(57627)) // Charge 6 sec post-affect - damage *= 2; - } - // Steady Shot - else if (m_spellInfo->SpellFamilyFlags[1] & 0x1) - { - bool found = false; - // check dazed affect - Unit::AuraEffectList const& decSpeedList = unitTarget->GetAuraEffectsByType(SPELL_AURA_MOD_DECREASE_SPEED); - for (Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter) - { - if ((*iter)->GetSpellInfo()->SpellIconID == 15 && (*iter)->GetSpellInfo()->Dispel == 0) - { - found = true; - break; - } - } - - /// @todo should this be put on taken but not done? - if (found) - damage += m_spellInfo->Effects[EFFECT_1].CalcValue(); - - if (Player* caster = m_caster->ToPlayer()) - { - // Add Ammo and Weapon damage plus RAP * 0.1 - if (Item* item = caster->GetWeaponForAttack(RANGED_ATTACK)) - { - ItemTemplate const* weaponTemplate = item->GetTemplate(); - float dmg_min = weaponTemplate->Damage[0].DamageMin; - float dmg_max = weaponTemplate->Damage[0].DamageMax; - if (dmg_max == 0.0f && dmg_min > dmg_max) - damage += int32(dmg_min); - else - damage += irand(int32(dmg_min), int32(dmg_max)); - damage += int32(caster->GetAmmoDPS() * weaponTemplate->Delay * 0.001f); - } - } - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Hammer of the Righteous - if (m_spellInfo->SpellFamilyFlags[1]&0x00040000) - { - float min_damage = m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE); - float max_damage = m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE); - if (Player* player = m_caster->ToPlayer()) // UNIT_FIELD_MINDAMAGE/MAXDAMAGE already include damage bonuses, so try to get them without damage bonuses - player->CalculateMinMaxDamage(BASE_ATTACK, false, false, min_damage, max_damage); - - float average = (min_damage + max_damage) / 2; - // Add main hand dps * effect[2] amount - int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_2); - damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK); - break; - } - // Shield of Righteousness - if (m_spellInfo->SpellFamilyFlags[EFFECT_1] & 0x100000) - { - uint8 level = m_caster->getLevel(); - uint32 block_value = m_caster->GetShieldBlockValue(uint32(float(level) * 29.5f), uint32(float(level) * 39.5f)); - damage += CalculatePct(block_value, m_spellInfo->Effects[EFFECT_1].CalcValue()); - break; - } - break; - } case SPELLFAMILY_DEATHKNIGHT: { // Blood Boil - bonus for diseased targets @@ -755,15 +627,6 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) // special cases switch (triggered_spell_id) { - // Mirror Image - case 58832: - { - // Glyph of Mirror Image - if (m_caster->HasAura(63093)) - m_caster->CastSpell(m_caster, 65047, true); // Mirror Image - - break; - } // Vanish (not exist) case 18461: { @@ -796,10 +659,6 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) unitTarget->CastSpell(unitTarget, 7870, true); return; } - // just skip - case 23770: // Sayge's Dark Fortune of * - // not exist, common cooldown can be implemented in scripts if need. - return; // Brittle Armor - (need add max stack of 24575 Brittle Armor) case 29284: { @@ -1261,12 +1120,7 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex) damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE); - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - int32 power = damage; - if (powerType == POWER_MANA) - power -= unitTarget->GetSpellCritDamageReduction(power); - - int32 newDamage = -(unitTarget->ModifyPower(powerType, -int32(power))); + int32 newDamage = -(unitTarget->ModifyPower(powerType, -damage)); float gainMultiplier = 0.0f; @@ -1344,12 +1198,7 @@ void Spell::EffectPowerBurn(SpellEffIndex effIndex) damage = std::min(damage, maxDamage); } - int32 power = damage; - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - if (powerType == POWER_MANA) - power -= unitTarget->GetSpellCritDamageReduction(power); - - int32 newDamage = -(unitTarget->ModifyPower(powerType, -power)); + int32 newDamage = -(unitTarget->ModifyPower(powerType, -damage)); // NO - Not a typo - EffectPowerBurn uses effect value multiplier - not effect damage multiplier float dmgMultiplier = m_spellInfo->Effects[effIndex].CalcValueMultiplier(m_originalCaster, this); @@ -1443,22 +1292,6 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/) //addhealth += tickheal * tickcount; //addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth, HEAL, unitTarget); } - // Nourish - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x2000000) - { - addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL); - - // Glyph of Nourish - if (AuraEffect const* aurEff = m_caster->GetAuraEffect(62971, 0)) - { - Unit::AuraEffectList const& Periodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); - for (Unit::AuraEffectList::const_iterator i = Periodic.begin(); i != Periodic.end(); ++i) - { - if (m_caster->GetGUID() == (*i)->GetCasterGUID()) - AddPct(addhealth, aurEff->GetAmount()); - } - } - } // Death Pact - return pct of max health to caster else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL); @@ -1604,7 +1437,7 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype) if (msg != EQUIP_ERR_OK) { // convert to possible store amount - if (msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) + if (msg == EQUIP_ERR_INV_FULL || msg == EQUIP_ERR_ITEM_MAX_COUNT) num_to_add -= no_space; else { @@ -1633,6 +1466,11 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype) // send info to the client player->SendNewItem(pItem, num_to_add, true, bgType == 0); + if (pProto->Quality > ITEM_QUALITY_EPIC || (pProto->Quality == ITEM_QUALITY_EPIC && pProto->ItemLevel >= MinNewsItemLevel[sWorld->getIntConfig(CONFIG_EXPANSION)])) + if (Guild* guild = player->GetGuild()) + guild->AddGuildNews(GUILD_NEWS_ITEM_CRAFTED, player->GetGUID(), 0, pProto->ItemId); + + // we succeeded in creating at least one item, so a levelup is possible if (bgType == 0) player->UpdateCraftSkill(m_spellInfo->Id); @@ -1721,7 +1559,7 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex) if (!caster->IsInWorld()) return; DynamicObject* dynObj = new DynamicObject(false); - if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), caster, m_spellInfo->Id, *destTarget, radius, DYNAMIC_OBJECT_AREA_SPELL)) + if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_AREA_SPELL)) { delete dynObj; return; @@ -1779,13 +1617,10 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) level_multiplier = 4; break; case 31930: // Judgements of the Wise - case 63375: // Improved Stormstrike + case 63375: // Primal Wisdom case 68082: // Glyph of Seal of Command damage = int32(CalculatePct(unitTarget->GetCreateMana(), damage)); break; - case 48542: // Revitalize - damage = int32(CalculatePct(unitTarget->GetMaxPower(power), damage)); - break; case 67490: // Runic Mana Injector (mana gain increased by 25% for engineers - 3.2.0 patch change) { if (Player* player = m_caster->ToPlayer()) @@ -1793,9 +1628,6 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) AddPct(damage, 25); break; } - case 71132: // Glyph of Shadow Word: Pain - damage = int32(CalculatePct(unitTarget->GetCreateMana(), 1)); // set 1 as value, missing in dbc - break; default: break; } @@ -1803,7 +1635,7 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) if (level_diff > 0) damage -= level_multiplier * level_diff; - if (damage < 0) + if (damage < 0 && power != POWER_ECLIPSE) return; m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power); @@ -2141,9 +1973,9 @@ void Spell::EffectSummonChangeItem(SpellEffIndex effIndex) uint8 msg = player->CanEquipItem(m_CastItem->GetSlot(), dest, pNewItem, true); - if (msg == EQUIP_ERR_OK || msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) + if (msg == EQUIP_ERR_OK || msg == EQUIP_ERR_CLIENT_LOCKED_OUT) { - if (msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) dest = EQUIPMENT_SLOT_MAINHAND; + if (msg == EQUIP_ERR_CLIENT_LOCKED_OUT) dest = EQUIPMENT_SLOT_MAINHAND; // prevent crash at access and unexpected charges counting with item update queue corrupt if (m_CastItem == m_targets.GetItemTarget()) @@ -2484,7 +2316,7 @@ void Spell::EffectDispel(SpellEffIndex effIndex) // Devour Magic if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->GetCategory() == SPELLCATEGORY_DEVOUR_MAGIC) { - int32 heal_amount = m_spellInfo->Effects[EFFECT_1].CalcValue(); + int32 heal_amount = m_spellInfo->Effects[EFFECT_1].CalcValue(m_caster); m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true); // Glyph of Felhunter if (Unit* owner = m_caster->GetOwner()) @@ -2559,7 +2391,7 @@ void Spell::EffectAddFarsight(SpellEffIndex effIndex) return; DynamicObject* dynObj = new DynamicObject(true); - if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, *destTarget, radius, DYNAMIC_OBJECT_FARSIGHT_FOCUS)) + if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_FARSIGHT_FOCUS)) { delete dynObj; return; @@ -2624,7 +2456,7 @@ void Spell::EffectLearnSkill(SpellEffIndex effIndex) unitTarget->ToPlayer()->SetSkill(skillid, m_spellInfo->Effects[effIndex].CalcValue(), std::max<uint16>(skillval, 1), tier->MaxSkill[damage - 1]); } -void Spell::EffectAddHonor(SpellEffIndex /*effIndex*/) +void Spell::EffectPlayMovie(SpellEffIndex effIndex) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -2632,27 +2464,11 @@ void Spell::EffectAddHonor(SpellEffIndex /*effIndex*/) if (unitTarget->GetTypeId() != TYPEID_PLAYER) return; - // not scale value for item based reward (/10 value expected) - if (m_CastItem) - { - unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage/10); - TC_LOG_DEBUG("spells", "SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(), unitTarget->ToPlayer()->GetGUIDLow()); + uint32 movieId = GetSpellInfo()->Effects[effIndex].MiscValue; + if (!sMovieStore.LookupEntry(movieId)) return; - } - // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80 - if (damage <= 50) - { - uint32 honor_reward = Trinity::Honor::hk_honor_at_level(unitTarget->getLevel(), float(damage)); - unitTarget->ToPlayer()->RewardHonor(NULL, 1, honor_reward); - TC_LOG_DEBUG("spells", "SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, unitTarget->ToPlayer()->GetGUIDLow()); - } - else - { - //maybe we have correct honor_gain in damage already - unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage); - TC_LOG_DEBUG("spells", "SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, unitTarget->ToPlayer()->GetGUIDLow()); - } + unitTarget->ToPlayer()->SendMovieStart(movieId); } void Spell::EffectTradeSkill(SpellEffIndex /*effIndex*/) @@ -2680,7 +2496,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex) return; // Handle vellums - if (itemTarget->IsWeaponVellum() || itemTarget->IsArmorVellum()) + if (itemTarget->IsVellum()) { // destroy one vellum from stack uint32 count = 1; @@ -2804,58 +2620,6 @@ void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex) if (!player) return; - // Rockbiter Weapon apply to both weapon - if (!itemTarget) - return; - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x400000) - { - uint32 spell_id = 0; - - // enchanting spell selected by calculated damage-per-sec stored in Effect[1] base value - // Note: damage calculated (correctly) with rounding int32(float(v)) but - // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime - switch (damage) - { - // Rank 1 - case 2: spell_id = 36744; break; // 0% [ 7% == 2, 14% == 2, 20% == 2] - // Rank 2 - case 4: spell_id = 36753; break; // 0% [ 7% == 4, 14% == 4] - case 5: spell_id = 36751; break; // 20% - // Rank 3 - case 6: spell_id = 36754; break; // 0% [ 7% == 6, 14% == 6] - case 7: spell_id = 36755; break; // 20% - // Rank 4 - case 9: spell_id = 36761; break; // 0% [ 7% == 6] - case 10: spell_id = 36758; break; // 14% - case 11: spell_id = 36760; break; // 20% - default: - TC_LOG_ERROR("spells", "Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW", damage); - return; - } - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); - if (!spellInfo) - { - TC_LOG_ERROR("spells", "Spell::EffectEnchantItemTmp: unknown spell id %i", spell_id); - return; - - } - - for (int j = BASE_ATTACK; j <= OFF_ATTACK; ++j) - { - if (Item* item = player->GetWeaponForAttack(WeaponAttackType(j))) - { - if (item->IsFitToSpellRequirements(m_spellInfo)) - { - Spell* spell = new Spell(m_caster, spellInfo, TRIGGERED_FULL_MASK); - SpellCastTargets targets; - targets.SetItemTarget(item); - spell->prepare(&targets); - } - } - } - return; - } if (!itemTarget) return; @@ -3106,9 +2870,6 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/) return; } - if (m_spellInfo->Id == 62124) - m_caster->CastSpell(unitTarget, 67485, true); - // Also use this effect to set the taunter's threat to the taunted creature's highest value if (unitTarget->getThreatManager().getCurrentVictim()) { @@ -3170,74 +2931,26 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) if (Aura* aur = unitTarget->GetAura(58567, m_caster->GetGUID())) { - // 58388 - Glyph of Devastate dummy aura. - if (int32 num = (needCast ? 0 : 1) + (m_caster->HasAura(58388) ? 1 : 0)) + if (int32 num = (needCast ? 0 : 1)) aur->ModStackAmount(num); fixed_bonus += (aur->GetStackAmount() - 1) * CalculateDamage(2, unitTarget); } } - if (m_spellInfo->SpellFamilyFlags[0] & 0x8000000) // Mocking Blow - { - if (unitTarget->IsImmunedToSpellEffect(m_spellInfo, EFFECT_1) || unitTarget->GetTypeId() == TYPEID_PLAYER) - { - m_damage = 0; - return; - } - } break; } case SPELLFAMILY_ROGUE: { - // Fan of Knives, Hemorrhage, Ghostly Strike - if ((m_spellInfo->SpellFamilyFlags[1] & 0x40000) - || (m_spellInfo->SpellFamilyFlags[0] & 0x6000000)) + // Hemorrhage + if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000) { - // Hemorrhage - if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000) - { - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->AddComboPoints(unitTarget, 1, this); - } + if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->AddComboPoints(unitTarget, 1, this); // 50% more damage with daggers if (m_caster->GetTypeId() == TYPEID_PLAYER) if (Item* item = m_caster->ToPlayer()->GetWeaponForAttack(m_attackType, true)) if (item->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER) totalDamagePercentMod *= 1.5f; } - // Mutilate (for each hand) - else if (m_spellInfo->SpellFamilyFlags[1] & 0x6) - { - bool found = false; - // fast check - if (unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON, m_spellInfo, m_caster)) - found = true; - // full aura scan - else - { - Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - if (itr->second->GetBase()->GetSpellInfo()->Dispel == DISPEL_POISON) - { - found = true; - break; - } - } - } - - if (found) - totalDamagePercentMod *= 1.2f; // 120% if poisoned - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Seal of Command Unleashed - if (m_spellInfo->Id == 20467) - { - spell_bonus += int32(0.08f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK)); - spell_bonus += int32(0.13f * m_caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask())); - } break; } case SPELLFAMILY_SHAMAN: @@ -3268,54 +2981,35 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) { // Kill Shot - bonus damage from Ranged Attack Power if (m_spellInfo->SpellFamilyFlags[1] & 0x800000) - spell_bonus += int32(0.4f * m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)); + spell_bonus += int32(0.45f * m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)); break; } case SPELLFAMILY_DEATHKNIGHT: { - // Plague Strike - if (m_spellInfo->SpellFamilyFlags[0] & 0x1) - { - // Glyph of Plague Strike - if (AuraEffect const* aurEff = m_caster->GetAuraEffect(58657, EFFECT_0)) - AddPct(totalDamagePercentMod, aurEff->GetAmount()); - break; - } // Blood Strike if (m_spellInfo->SpellFamilyFlags[0] & 0x400000) { - float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue() * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) / 2.0f; + float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) / 2.0f; // Death Knight T8 Melee 4P Bonus if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0)) AddPct(bonusPct, aurEff->GetAmount()); AddPct(totalDamagePercentMod, bonusPct); - - // Glyph of Blood Strike - if (m_caster->GetAuraEffect(59332, EFFECT_0)) - if (unitTarget->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED)) - AddPct(totalDamagePercentMod, 20); break; } // Death Strike if (m_spellInfo->SpellFamilyFlags[0] & 0x10) { // Glyph of Death Strike + // 2% more damage per 5 runic power, up to a maximum of 40% if (AuraEffect const* aurEff = m_caster->GetAuraEffect(59336, EFFECT_0)) - if (uint32 runic = std::min<uint32>(m_caster->GetPower(POWER_RUNIC_POWER), aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue())) + if (uint32 runic = std::min<uint32>(uint32(m_caster->GetPower(POWER_RUNIC_POWER) / 2.5f), aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(m_caster))) AddPct(totalDamagePercentMod, runic); break; } // Obliterate (12.5% more damage per disease) if (m_spellInfo->SpellFamilyFlags[1] & 0x20000) { - bool consumeDiseases = true; - // Annihilation - if (AuraEffect const* aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2710, EFFECT_0)) - // Do not consume diseases if roll sucesses - if (roll_chance_i(aurEff->GetAmount())) - consumeDiseases = false; - - float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue() * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), consumeDiseases) / 2.0f; + float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), false) / 2.0f; // Death Knight T8 Melee 4P Bonus if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0)) AddPct(bonusPct, aurEff->GetAmount()); @@ -3331,7 +3025,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) // Heart Strike if (m_spellInfo->SpellFamilyFlags[0] & 0x1000000) { - float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue() * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()); + float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()); // Death Knight T8 Melee 4P Bonus if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0)) AddPct(bonusPct, aurEff->GetAmount()); @@ -3475,7 +3169,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex) // check if we can interrupt spell if ((spell->getState() == SPELL_STATE_CASTING || (spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f)) - && curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE + && (curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE || curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_UNK) && ((i == CURRENT_GENERIC_SPELL && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT) || (i == CURRENT_CHANNELED_SPELL && curSpellInfo->ChannelInterruptFlags & CHANNEL_INTERRUPT_FLAG_INTERRUPT))) { @@ -3519,6 +3213,9 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) return; } + for (auto phase : m_caster->GetPhases()) + pGameObj->SetInPhase(phase, false, true); + int32 duration = m_spellInfo->GetDuration(); pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); @@ -3540,6 +3237,9 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (linkedGO->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map, m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { + for (auto phase : m_caster->GetPhases()) + linkedGO->SetInPhase(phase, false, true); + linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); linkedGO->SetSpellId(m_spellInfo->Id); @@ -4098,7 +3798,7 @@ void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/) // Vanish allows to remove all threat and cast regular stealth so other spells can be used if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE - && (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VANISH)) + && (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG0_ROGUE_VANISH)) { m_caster->ToPlayer()->RemoveAurasByType(SPELL_AURA_MOD_ROOT); // Overkill @@ -4161,7 +3861,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) Map* map = m_caster->GetMap(); if (!pGameObj->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, - map, m_caster->GetPhaseMask(), + map, 0, m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2, m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2, m_caster->GetPositionZ(), @@ -4171,6 +3871,9 @@ void Spell::EffectDuel(SpellEffIndex effIndex) return; } + for (auto phase : m_caster->GetPhases()) + pGameObj->SetInPhase(phase, false, true); + pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction()); pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1); int32 duration = m_spellInfo->GetDuration(); @@ -4301,12 +4004,16 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex) switch (m_glyphIndex) { case 0: - case 1: minLevel = 15; break; - case 2: minLevel = 50; break; - case 3: minLevel = 30; break; - case 4: minLevel = 70; break; - case 5: minLevel = 80; break; + case 1: + case 6: minLevel = 25; break; + case 2: + case 3: + case 7: minLevel = 50; break; + case 4: + case 5: + case 8: minLevel = 75; break; } + if (minLevel && m_caster->getLevel() < minLevel) { SendCastResult(SPELL_FAILED_GLYPH_SOCKET_LOCKED); @@ -4314,13 +4021,13 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex) } // apply new one - if (uint32 glyph = m_spellInfo->Effects[effIndex].MiscValue) + if (uint32 newGlyph = m_spellInfo->Effects[effIndex].MiscValue) { - if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph)) + if (GlyphPropertiesEntry const* newGlyphProperties = sGlyphPropertiesStore.LookupEntry(newGlyph)) { - if (GlyphSlotEntry const* gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex))) + if (GlyphSlotEntry const* newGlyphSlot = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex))) { - if (gp->TypeFlags != gs->TypeFlags) + if (newGlyphProperties->TypeFlags != newGlyphSlot->TypeFlags) { SendCastResult(SPELL_FAILED_INVALID_GLYPH); return; // glyph slot mismatch @@ -4328,17 +4035,26 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex) } // remove old glyph - if (uint32 oldglyph = player->GetGlyph(m_glyphIndex)) + if (uint32 oldGlyph = player->GetGlyph(player->GetActiveSpec(), m_glyphIndex)) { - if (GlyphPropertiesEntry const* old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph)) + if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph)) { - player->RemoveAurasDueToSpell(old_gp->SpellId); + player->RemoveAurasDueToSpell(oldGlyphProperties->SpellId); player->SetGlyph(m_glyphIndex, 0); } } - player->CastSpell(m_caster, gp->SpellId, true); - player->SetGlyph(m_glyphIndex, glyph); + player->CastSpell(m_caster, newGlyphProperties->SpellId, true); + player->SetGlyph(m_glyphIndex, newGlyph); + player->SendTalentsInfoData(false); + } + } + else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveSpec(), m_glyphIndex)) // Removing the glyph, get the old one + { + if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph)) + { + player->RemoveAurasDueToSpell(oldGlyphProperties->SpellId); + player->SetGlyph(m_glyphIndex, 0); player->SendTalentsInfoData(false); } } @@ -4508,12 +4224,15 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) Map* map = m_caster->GetMap(); if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, - m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + 0, x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) { delete go; return; } + for (auto phase : m_caster->GetPhases()) + go->SetInPhase(phase, false, true); + //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); int32 duration = m_spellInfo->GetDuration(); go->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); @@ -4540,7 +4259,7 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) Player* target = unitTarget->ToPlayer(); - if (target->isResurrectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = target->CountPctFromMaxHealth(damage); @@ -4548,7 +4267,7 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) ExecuteLogEffectResurrect(effIndex, target); - target->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana); + target->SetResurrectRequestData(m_caster, health, mana, 0); SendResurrectRequest(target); } @@ -4695,6 +4414,7 @@ void Spell::EffectSelfResurrect(SpellEffIndex effIndex) player->SetPower(POWER_MANA, mana); player->SetPower(POWER_RAGE, 0); player->SetPower(POWER_ENERGY, player->GetMaxPower(POWER_ENERGY)); + player->SetPower(POWER_FOCUS, 0); player->SpawnCorpseBones(); } @@ -5137,12 +4857,15 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) GameObject* pGameObj = new GameObject; if (!pGameObj->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap, - m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + 0, fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { delete pGameObj; return; } + for (auto phase : m_caster->GetPhases()) + pGameObj->SetInPhase(phase, false, true); + int32 duration = m_spellInfo->GetDuration(); switch (goinfo->type) @@ -5203,8 +4926,11 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) { GameObject* linkedGO = new GameObject; if (linkedGO->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap, - m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + 0, fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { + for (auto phase : m_caster->GetPhases()) + linkedGO->SetInPhase(phase, false, true); + linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); linkedGO->SetSpellId(m_spellInfo->Id); @@ -5568,6 +5294,11 @@ void Spell::EffectCreateTamedPet(SpellEffIndex effIndex) if (!pet) return; + // relocate + float px, py, pz; + unitTarget->GetClosePoint(px, py, pz, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle()); + pet->Relocate(px, py, pz, unitTarget->GetOrientation()); + // add to world pet->GetMap()->AddToMap(pet->ToCreature()); @@ -5752,6 +5483,7 @@ void Spell::EffectPlayMusic(SpellEffIndex effIndex) WorldPacket data(SMSG_PLAY_MUSIC, 4); data << uint32(soundid); + data << uint64(unitTarget->GetGUID()); unitTarget->ToPlayer()->GetSession()->SendPacket(&data); } @@ -5787,8 +5519,7 @@ void Spell::EffectPlaySound(SpellEffIndex effIndex) switch (m_spellInfo->Id) { - case 58730: // Restricted Flight Area - case 58600: // Restricted Flight Area + case 91604: // Restricted Flight Area unitTarget->ToPlayer()->GetSession()->SendNotification(LANG_ZONE_NOFLYZONE); break; default: @@ -5805,6 +5536,7 @@ void Spell::EffectPlaySound(SpellEffIndex effIndex) WorldPacket data(SMSG_PLAY_SOUND, 4); data << uint32(soundId); + data << uint64(m_caster->GetGUID()); unitTarget->ToPlayer()->GetSession()->SendPacket(&data); } @@ -5819,6 +5551,28 @@ void Spell::EffectRemoveAura(SpellEffIndex effIndex) unitTarget->RemoveAurasDueToSpell(m_spellInfo->Effects[effIndex].TriggerSpell); } +void Spell::EffectDamageFromMaxHealthPCT(SpellEffIndex /*effIndex*/) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget) + return; + + m_damage += unitTarget->CountPctFromMaxHealth(damage); +} + +void Spell::EffectGiveCurrency(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->ModifyCurrency(m_spellInfo->Effects[effIndex].MiscValue, damage); +} + void Spell::EffectCastButtons(SpellEffIndex effIndex) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) @@ -5850,10 +5604,10 @@ void Spell::EffectCastButtons(SpellEffIndex effIndex) if (!p_caster->HasSpell(spell_id) || p_caster->HasSpellCooldown(spell_id)) continue; - if (!(spellInfo->AttributesEx7 & SPELL_ATTR7_SUMMON_PLAYER_TOTEM)) + if (!(spellInfo->AttributesEx9 & SPELL_ATTR9_SUMMON_PLAYER_TOTEM)) continue; - uint32 cost = spellInfo->CalcPowerCost(m_caster, spellInfo->GetSchoolMask()); + int32 cost = spellInfo->CalcPowerCost(m_caster, spellInfo->GetSchoolMask()); if (m_caster->GetPower(POWER_MANA) < cost) continue; @@ -5944,3 +5698,65 @@ void Spell::EffectSummonRaFFriend(SpellEffIndex effIndex) m_caster->CastSpell(unitTarget, m_spellInfo->Effects[effIndex].TriggerSpell, true); } + +void Spell::EffectUnlockGuildVaultTab(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) + return; + + // Safety checks done in Spell::CheckCast + Player* caster = m_caster->ToPlayer(); + if (Guild* guild = caster->GetGuild()) + guild->HandleBuyBankTab(caster->GetSession(), m_spellInfo->Effects[effIndex].BasePoints - 1); // Bank tabs start at zero internally +} + +void Spell::EffectResurrectWithAura(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || !unitTarget->IsInWorld()) + return; + + Player* target = unitTarget->ToPlayer(); + if (!target) + return; + + if (unitTarget->IsAlive()) + return; + + if (target->IsResurrectRequested()) // already have one active request + return; + + uint32 health = target->CountPctFromMaxHealth(damage); + uint32 mana = CalculatePct(target->GetMaxPower(POWER_MANA), damage); + uint32 resurrectAura = 0; + if (sSpellMgr->GetSpellInfo(GetSpellInfo()->Effects[effIndex].TriggerSpell)) + resurrectAura = GetSpellInfo()->Effects[effIndex].TriggerSpell; + + if (resurrectAura && target->HasAura(resurrectAura)) + return; + + ExecuteLogEffectResurrect(effIndex, target); + target->SetResurrectRequestData(m_caster, health, mana, resurrectAura); + SendResurrectRequest(target); +} + +void Spell::EffectCreateAreaTrigger(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) + return; + + Position pos; + if (!m_targets.HasDst()) + pos = GetCaster()->GetPosition(); + else + pos = destTarget->GetPosition(); + + // trigger entry/miscvalue relation is currently unknown, for now use MiscValue as trigger entry + uint32 triggerEntry = GetSpellInfo()->Effects[effIndex].MiscValue; + + AreaTrigger * areaTrigger = new AreaTrigger; + if (!areaTrigger->CreateAreaTrigger(sObjectMgr->GenerateLowGuid(HIGHGUID_AREATRIGGER), triggerEntry, GetCaster(), GetSpellInfo(), pos)) + delete areaTrigger; +} diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 99c3d234ef8..4b6e4dc2ee7 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -15,8 +15,9 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "SpellAuraDefines.h" #include "SpellInfo.h" +#include "SpellAuraDefines.h" +#include "SpellAuraEffects.h" #include "SpellMgr.h" #include "Spell.h" #include "DBCStores.h" @@ -318,34 +319,57 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 107 TARGET_UNK_DEST_AREA_UNK_107 {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 108 TARGET_GAMEOBJECT_CONE {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 109 - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 110 TARGET_DEST_UNK_110 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 110 TARGET_DEST_UNK_110 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 111 + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 112 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 113 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 114 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 115 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 116 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 117 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 118 + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_RAID, TARGET_DIR_NONE}, // 119 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 120 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 121 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 122 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 123 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 124 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 125 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 126 + {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 127 }; -SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex) +SpellEffectInfo::SpellEffectInfo(SpellEntry const* /*spellEntry*/, SpellInfo const* spellInfo, uint8 effIndex, SpellEffectEntry const* _effect) { + SpellScalingEntry const* scaling = spellInfo->GetSpellScaling(); + _spellInfo = spellInfo; - _effIndex = effIndex; - Effect = spellEntry->Effect[effIndex]; - ApplyAuraName = spellEntry->EffectApplyAuraName[effIndex]; - Amplitude = spellEntry->EffectAmplitude[effIndex]; - DieSides = spellEntry->EffectDieSides[effIndex]; - RealPointsPerLevel = spellEntry->EffectRealPointsPerLevel[effIndex]; - BasePoints = spellEntry->EffectBasePoints[effIndex]; - PointsPerComboPoint = spellEntry->EffectPointsPerComboPoint[effIndex]; - ValueMultiplier = spellEntry->EffectValueMultiplier[effIndex]; - DamageMultiplier = spellEntry->EffectDamageMultiplier[effIndex]; - BonusMultiplier = spellEntry->EffectBonusMultiplier[effIndex]; - MiscValue = spellEntry->EffectMiscValue[effIndex]; - MiscValueB = spellEntry->EffectMiscValueB[effIndex]; - Mechanic = Mechanics(spellEntry->EffectMechanic[effIndex]); - TargetA = SpellImplicitTargetInfo(spellEntry->EffectImplicitTargetA[effIndex]); - TargetB = SpellImplicitTargetInfo(spellEntry->EffectImplicitTargetB[effIndex]); - RadiusEntry = spellEntry->EffectRadiusIndex[effIndex] ? sSpellRadiusStore.LookupEntry(spellEntry->EffectRadiusIndex[effIndex]) : NULL; - ChainTarget = spellEntry->EffectChainTarget[effIndex]; - ItemType = spellEntry->EffectItemType[effIndex]; - TriggerSpell = spellEntry->EffectTriggerSpell[effIndex]; - SpellClassMask = spellEntry->EffectSpellClassMask[effIndex]; + _effIndex = _effect ? _effect->EffectIndex : effIndex; + Effect = _effect ? _effect->Effect : 0; + ApplyAuraName = _effect ? _effect->EffectApplyAuraName : 0; + Amplitude = _effect ? _effect->EffectAmplitude : 0; + DieSides = _effect ? _effect->EffectDieSides : 0; + RealPointsPerLevel = _effect ? _effect->EffectRealPointsPerLevel : 0.0f; + BasePoints = _effect ? _effect->EffectBasePoints : 0; + PointsPerComboPoint = _effect ? _effect->EffectPointsPerComboPoint : 0.0f; + ValueMultiplier = _effect ? _effect->EffectValueMultiplier : 0.0f; + DamageMultiplier = _effect ? _effect->EffectDamageMultiplier : 0.0f; + BonusMultiplier = _effect ? _effect->EffectBonusMultiplier : 0.0f; + MiscValue = _effect ? _effect->EffectMiscValue : 0; + MiscValueB = _effect ? _effect->EffectMiscValueB : 0; + Mechanic = Mechanics(_effect ? _effect->EffectMechanic : 0); + TargetA = SpellImplicitTargetInfo(_effect ? _effect->EffectImplicitTargetA : 0); + TargetB = SpellImplicitTargetInfo(_effect ? _effect->EffectImplicitTargetB : 0); + RadiusEntry = _effect && _effect->EffectRadiusIndex ? sSpellRadiusStore.LookupEntry(_effect->EffectRadiusIndex) : NULL; + MaxRadiusEntry = _effect && _effect->EffectRadiusMaxIndex ? sSpellRadiusStore.LookupEntry(_effect->EffectRadiusMaxIndex) : NULL; + ChainTarget = _effect ? _effect->EffectChainTarget : 0; + ItemType = _effect ? _effect->EffectItemType : 0; + TriggerSpell = _effect ? _effect->EffectTriggerSpell : 0; + SpellClassMask = _effect ? _effect->EffectSpellClassMask : flag96(0); ImplicitTargetConditions = NULL; + ScalingMultiplier = scaling ? scaling->Multiplier[_effIndex] : 0.0f; + DeltaScalingMultiplier = scaling ? scaling->RandomMultiplier[_effIndex] : 0.0f; + ComboScalingMultiplier = scaling ? scaling->OtherMultiplier[_effIndex] : 0.0f; } bool SpellEffectInfo::IsEffect() const @@ -404,37 +428,73 @@ bool SpellEffectInfo::IsUnitOwnedAuraEffect() const return IsAreaAuraEffect() || Effect == SPELL_EFFECT_APPLY_AURA; } -int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const* /*target*/) const +int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const* target) const { float basePointsPerLevel = RealPointsPerLevel; int32 basePoints = bp ? *bp : BasePoints; - int32 randomPoints = int32(DieSides); + float comboDamage = PointsPerComboPoint; // base amount modification based on spell lvl vs caster lvl - if (caster) + if (ScalingMultiplier != 0.0f) { - int32 level = int32(caster->getLevel()); - if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0) - level = int32(_spellInfo->MaxLevel); - else if (level < int32(_spellInfo->BaseLevel)) - level = int32(_spellInfo->BaseLevel); - level -= int32(_spellInfo->SpellLevel); - basePoints += int32(level * basePointsPerLevel); - } + if (caster) + { + int32 level = caster->getLevel(); + if (target && _spellInfo->IsPositiveEffect(_effIndex) && (Effect == SPELL_EFFECT_APPLY_AURA)) + level = target->getLevel(); + + if (GtSpellScalingEntry const* gtScaling = sGtSpellScalingStore.LookupEntry((_spellInfo->ScalingClass != -1 ? _spellInfo->ScalingClass - 1 : MAX_CLASSES - 1) * 100 + level - 1)) + { + float multiplier = gtScaling->value; + if (_spellInfo->CastTimeMax > 0 && _spellInfo->CastTimeMaxLevel > level) + multiplier *= float(_spellInfo->CastTimeMin + (level - 1) * (_spellInfo->CastTimeMax - _spellInfo->CastTimeMin) / (_spellInfo->CastTimeMaxLevel - 1)) / float(_spellInfo->CastTimeMax); + if (_spellInfo->CoefLevelBase > level) + multiplier *= (1.0f - _spellInfo->CoefBase) * (float)(level - 1) / (float)(_spellInfo->CoefLevelBase - 1) + _spellInfo->CoefBase; + + float preciseBasePoints = ScalingMultiplier * multiplier; + if (DeltaScalingMultiplier) + { + float delta = fabs(DeltaScalingMultiplier * ScalingMultiplier * multiplier * 0.5f); + preciseBasePoints += frand(-delta, delta); + } - // roll in a range <1;EffectDieSides> as of patch 3.3.3 - switch (randomPoints) + basePoints = int32(preciseBasePoints); + + if (ComboScalingMultiplier) + comboDamage = ComboScalingMultiplier * multiplier; + } + } + } + else { - case 0: break; - case 1: basePoints += 1; break; // range 1..1 - default: - // range can have positive (1..rand) and negative (rand..1) values, so order its for irand - int32 randvalue = (randomPoints >= 1) - ? irand(1, randomPoints) - : irand(randomPoints, 1); + if (caster) + { + int32 level = int32(caster->getLevel()); + if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0) + level = int32(_spellInfo->MaxLevel); + else if (level < int32(_spellInfo->BaseLevel)) + level = int32(_spellInfo->BaseLevel); + level -= int32(_spellInfo->SpellLevel); + basePoints += int32(level * basePointsPerLevel); + } - basePoints += randvalue; - break; + // roll in a range <1;EffectDieSides> as of patch 3.3.3 + int32 randomPoints = int32(DieSides); + switch (randomPoints) + { + case 0: break; + case 1: basePoints += 1; break; // range 1..1 + default: + { + // range can have positive (1..rand) and negative (rand..1) values, so order its for irand + int32 randvalue = (randomPoints >= 1) + ? irand(1, randomPoints) + : irand(randomPoints, 1); + + basePoints += randvalue; + break; + } + } } float value = float(basePoints); @@ -443,14 +503,26 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const if (caster) { // bonus amount from combo points - if (caster->m_movedPlayer) + if (caster->m_movedPlayer && comboDamage) if (uint8 comboPoints = caster->m_movedPlayer->GetComboPoints()) - if (float comboDamage = PointsPerComboPoint) - value += comboDamage* comboPoints; + value += comboDamage * comboPoints; value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value); // amount multiplication based on caster's level +/* REVIEW - MERGE <<<<<<< HEAD + if (!_spellInfo->GetSpellScaling() && !basePointsPerLevel && (_spellInfo->Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION && _spellInfo->SpellLevel) && + Effect != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && + Effect != SPELL_EFFECT_KNOCK_BACK && + Effect != SPELL_EFFECT_ADD_EXTRA_ATTACKS && + ApplyAuraName != SPELL_AURA_MOD_SPEED_ALWAYS && + ApplyAuraName != SPELL_AURA_MOD_SPEED_NOT_STACK && + ApplyAuraName != SPELL_AURA_MOD_INCREASE_SPEED && + ApplyAuraName != SPELL_AURA_MOD_DECREASE_SPEED) + //there are many more: slow speed, -healing pct + value *= 0.25f * exp(caster->getLevel() * (70 - _spellInfo->SpellLevel) / 1000.0f); + //value = int32(value * (int32)getLevel() / (int32)(_spellInfo->spellLevel ? _spellInfo->spellLevel : 1)); +======= */ if (!caster->IsControlledByPlayer() && _spellInfo->SpellLevel && _spellInfo->SpellLevel != caster->getLevel() && !basePointsPerLevel && (_spellInfo->Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)) @@ -501,6 +573,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const value *= casterScaler->ratio / spellScaler->ratio; } } +// REVIEW - MERGE >>>>>>> master } return int32(value); @@ -535,16 +608,25 @@ bool SpellEffectInfo::HasRadius() const return RadiusEntry != NULL; } +bool SpellEffectInfo::HasMaxRadius() const +{ + return MaxRadiusEntry != NULL; +} + float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const { - if (!HasRadius()) + const SpellRadiusEntry* entry = RadiusEntry; + if (!HasRadius() && HasMaxRadius()) + entry = MaxRadiusEntry; + + if (!entry) return 0.0f; - float radius = RadiusEntry->RadiusMin; + float radius = entry->RadiusMin; if (caster) { - radius += RadiusEntry->RadiusPerLevel * caster->getLevel(); - radius = std::min(radius, RadiusEntry->RadiusMax); + radius += entry->RadiusPerLevel * caster->getLevel(); + radius = std::min(radius, entry->RadiusMax); if (Player* modOwner = caster->GetSpellModOwner()) modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell); } @@ -591,7 +673,7 @@ SpellTargetObjectTypes SpellEffectInfo::GetUsedTargetObjectType() const return _data[Effect].UsedTargetObjectType; } -SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = +SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = { // implicit target type used target object type {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 0 @@ -759,14 +841,29 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 162 SPELL_EFFECT_TALENT_SPEC_SELECT {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 163 SPELL_EFFECT_163 {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 164 SPELL_EFFECT_REMOVE_AURA + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 165 SPELL_EFFECT_165 + {EFFECT_IMPLICIT_TARGET_CASTER, TARGET_OBJECT_TYPE_UNIT}, // 166 SPELL_EFFECT_GIVE_CURRENCY + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 167 SPELL_EFFECT_167 + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 168 SPELL_EFFECT_168 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_ITEM}, // 169 SPELL_EFFECT_DESTROY_ITEM + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 170 SPELL_EFFECT_170 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_DEST}, // 171 SPELL_EFFECT_171 + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 172 SPELL_EFFECT_172 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 173 SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 174 SPELL_EFFECT_174 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 175 SPELL_EFFECT_175 + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 176 SPELL_EFFECT_176 + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 177 SPELL_EFFECT_177 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 178 SPELL_EFFECT_178 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_DEST}, // 179 SPELL_EFFECT_CREATE_AREATRIGGER + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 180 SPELL_EFFECT_180 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 181 SPELL_EFFECT_181 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_UNIT}, // 182 SPELL_EFFECT_182 }; -SpellInfo::SpellInfo(SpellEntry const* spellEntry) +SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effects) { Id = spellEntry->Id; - CategoryEntry = spellEntry->Category ? sSpellCategoryStore.LookupEntry(spellEntry->Category) : NULL; - Dispel = spellEntry->Dispel; - Mechanic = spellEntry->Mechanic; Attributes = spellEntry->Attributes; AttributesEx = spellEntry->AttributesEx; AttributesEx2 = spellEntry->AttributesEx2; @@ -775,82 +872,148 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry) AttributesEx5 = spellEntry->AttributesEx5; AttributesEx6 = spellEntry->AttributesEx6; AttributesEx7 = spellEntry->AttributesEx7; + AttributesEx8 = spellEntry->AttributesEx8; + AttributesEx9 = spellEntry->AttributesEx9; + AttributesEx10 = spellEntry->AttributesEx10; AttributesCu = 0; - Stances = spellEntry->Stances; - StancesNot = spellEntry->StancesNot; - Targets = spellEntry->Targets; - TargetCreatureType = spellEntry->TargetCreatureType; - RequiresSpellFocus = spellEntry->RequiresSpellFocus; - FacingCasterFlags = spellEntry->FacingCasterFlags; - CasterAuraState = spellEntry->CasterAuraState; - TargetAuraState = spellEntry->TargetAuraState; - CasterAuraStateNot = spellEntry->CasterAuraStateNot; - TargetAuraStateNot = spellEntry->TargetAuraStateNot; - CasterAuraSpell = spellEntry->casterAuraSpell; - TargetAuraSpell = spellEntry->targetAuraSpell; - ExcludeCasterAuraSpell = spellEntry->excludeCasterAuraSpell; - ExcludeTargetAuraSpell = spellEntry->excludeTargetAuraSpell; CastTimeEntry = spellEntry->CastingTimeIndex ? sSpellCastTimesStore.LookupEntry(spellEntry->CastingTimeIndex) : NULL; - RecoveryTime = spellEntry->RecoveryTime; - CategoryRecoveryTime = spellEntry->CategoryRecoveryTime; - StartRecoveryCategory = spellEntry->StartRecoveryCategory; - StartRecoveryTime = spellEntry->StartRecoveryTime; - InterruptFlags = spellEntry->InterruptFlags; - AuraInterruptFlags = spellEntry->AuraInterruptFlags; - ChannelInterruptFlags = spellEntry->ChannelInterruptFlags; - ProcFlags = spellEntry->procFlags; - ProcChance = spellEntry->procChance; - ProcCharges = spellEntry->procCharges; - MaxLevel = spellEntry->maxLevel; - BaseLevel = spellEntry->baseLevel; - SpellLevel = spellEntry->spellLevel; DurationEntry = spellEntry->DurationIndex ? sSpellDurationStore.LookupEntry(spellEntry->DurationIndex) : NULL; PowerType = spellEntry->powerType; - ManaCost = spellEntry->manaCost; - ManaCostPerlevel = spellEntry->manaCostPerlevel; - ManaPerSecond = spellEntry->manaPerSecond; - ManaPerSecondPerLevel = spellEntry->manaPerSecondPerLevel; - ManaCostPercentage = spellEntry->ManaCostPercentage; - RuneCostID = spellEntry->runeCostID; RangeEntry = spellEntry->rangeIndex ? sSpellRangeStore.LookupEntry(spellEntry->rangeIndex) : NULL; Speed = spellEntry->speed; - StackAmount = spellEntry->StackAmount; - for (uint8 i = 0; i < 2; ++i) - Totem[i] = spellEntry->Totem[i]; - - for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i) - Reagent[i] = spellEntry->Reagent[i]; - - for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i) - ReagentCount[i] = spellEntry->ReagentCount[i]; - - EquippedItemClass = spellEntry->EquippedItemClass; - EquippedItemSubClassMask = spellEntry->EquippedItemSubClassMask; - EquippedItemInventoryTypeMask = spellEntry->EquippedItemInventoryTypeMask; - for (uint8 i = 0; i < 2; ++i) - TotemCategory[i] = spellEntry->TotemCategory[i]; for (uint8 i = 0; i < 2; ++i) SpellVisual[i] = spellEntry->SpellVisual[i]; SpellIconID = spellEntry->SpellIconID; ActiveIconID = spellEntry->activeIconID; - for (uint8 i = 0; i < 16; ++i) - SpellName[i] = spellEntry->SpellName[i]; - - for (uint8 i = 0; i < 16; ++i) - Rank[i] = spellEntry->Rank[i]; - - MaxTargetLevel = spellEntry->MaxTargetLevel; - MaxAffectedTargets = spellEntry->MaxAffectedTargets; - SpellFamilyName = spellEntry->SpellFamilyName; - SpellFamilyFlags = spellEntry->SpellFamilyFlags; - DmgClass = spellEntry->DmgClass; - PreventionType = spellEntry->PreventionType; - AreaGroupId = spellEntry->AreaGroupId; + SpellName = spellEntry->SpellName; + Rank = spellEntry->Rank; SchoolMask = spellEntry->SchoolMask; + RuneCostID = spellEntry->runeCostID; + SpellDifficultyId = spellEntry->SpellDifficultyId; + SpellScalingId = spellEntry->SpellScalingId; + SpellAuraOptionsId = spellEntry->SpellAuraOptionsId; + SpellAuraRestrictionsId = spellEntry->SpellAuraRestrictionsId; + SpellCastingRequirementsId = spellEntry->SpellCastingRequirementsId; + SpellCategoriesId = spellEntry->SpellCategoriesId; + SpellClassOptionsId = spellEntry->SpellClassOptionsId; + SpellCooldownsId = spellEntry->SpellCooldownsId; + SpellEquippedItemsId = spellEntry->SpellEquippedItemsId; + SpellInterruptsId = spellEntry->SpellInterruptsId; + SpellLevelsId = spellEntry->SpellLevelsId; + SpellPowerId = spellEntry->SpellPowerId; + SpellReagentsId = spellEntry->SpellReagentsId; + SpellShapeshiftId = spellEntry->SpellShapeshiftId; + SpellTargetRestrictionsId = spellEntry->SpellTargetRestrictionsId; + SpellTotemsId = spellEntry->SpellTotemsId; + + // SpellDifficultyEntry for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - Effects[i] = SpellEffectInfo(spellEntry, this, i); + Effects[i] = SpellEffectInfo(spellEntry, this, i, effects[i]); + + // SpellScalingEntry + SpellScalingEntry const* _scaling = GetSpellScaling(); + CastTimeMin = _scaling ? _scaling->CastTimeMin : 0; + CastTimeMax = _scaling ?_scaling->CastTimeMax : 0; + CastTimeMaxLevel = _scaling ? _scaling->CastTimeMaxLevel : 0; + ScalingClass = _scaling ? _scaling->ScalingClass : 0; + CoefBase = _scaling ? _scaling->CoefBase : 0; + CoefLevelBase = _scaling ? _scaling->CoefLevelBase : 0; + + // SpellAuraOptionsEntry + SpellAuraOptionsEntry const* _options = GetSpellAuraOptions(); + ProcFlags = _options ? _options->procFlags : 0; + ProcChance = _options ? _options->procChance : 0; + ProcCharges = _options ? _options->procCharges : 0; + StackAmount = _options ? _options->StackAmount : 0; + + // SpellAuraRestrictionsEntry + SpellAuraRestrictionsEntry const* _aura = GetSpellAuraRestrictions(); + CasterAuraState = _aura ? _aura->CasterAuraState : 0; + TargetAuraState = _aura ? _aura->TargetAuraState : 0; + CasterAuraStateNot = _aura ? _aura->CasterAuraStateNot : 0; + TargetAuraStateNot = _aura ? _aura->TargetAuraStateNot : 0; + CasterAuraSpell = _aura ? _aura->casterAuraSpell : 0; + TargetAuraSpell = _aura ? _aura->targetAuraSpell : 0; + ExcludeCasterAuraSpell = _aura ? _aura->excludeCasterAuraSpell : 0; + ExcludeTargetAuraSpell = _aura ? _aura->excludeTargetAuraSpell : 0; + + // SpellCastingRequirementsEntry + SpellCastingRequirementsEntry const* _castreq = GetSpellCastingRequirements(); + RequiresSpellFocus = _castreq ? _castreq->RequiresSpellFocus : 0; + FacingCasterFlags = _castreq ? _castreq->FacingCasterFlags : 0; + AreaGroupId = _castreq ? _castreq->AreaGroupId : -1; + + // SpellCategoriesEntry + SpellCategoriesEntry const* _categorie = GetSpellCategories(); + CategoryEntry = _categorie ? sSpellCategoryStore.LookupEntry(_categorie->Category) : NULL; + Dispel = _categorie ? _categorie->Dispel : 0; + Mechanic = _categorie ? _categorie->Mechanic : 0; + StartRecoveryCategory = _categorie ? _categorie->StartRecoveryCategory : 0; + DmgClass = _categorie ? _categorie->DmgClass : 0; + PreventionType = _categorie ? _categorie->PreventionType : 0; + + // SpellClassOptionsEntry + SpellClassOptionsEntry const* _class = GetSpellClassOptions(); + SpellFamilyName = _class ? _class->SpellFamilyName : 0; + SpellFamilyFlags = _class ? _class->SpellFamilyFlags : flag96(0); + + // SpellCooldownsEntry + SpellCooldownsEntry const* _cooldowns = GetSpellCooldowns(); + RecoveryTime = _cooldowns ? _cooldowns->RecoveryTime : 0; + CategoryRecoveryTime = _cooldowns ? _cooldowns->CategoryRecoveryTime : 0; + StartRecoveryTime = _cooldowns ? _cooldowns->StartRecoveryTime : 0; + + // SpellEquippedItemsEntry + SpellEquippedItemsEntry const* _equipped = GetSpellEquippedItems(); + EquippedItemClass = _equipped ? _equipped->EquippedItemClass : -1; + EquippedItemSubClassMask = _equipped ?_equipped->EquippedItemSubClassMask : -1; + EquippedItemInventoryTypeMask = _equipped ? _equipped->EquippedItemInventoryTypeMask : -1; + + // SpellInterruptsEntry + SpellInterruptsEntry const* _interrupt = GetSpellInterrupts(); + InterruptFlags = _interrupt ? _interrupt->InterruptFlags : 0; + AuraInterruptFlags = _interrupt ? _interrupt->AuraInterruptFlags : 0; + ChannelInterruptFlags = _interrupt ? _interrupt->ChannelInterruptFlags : 0; + + // SpellLevelsEntry + SpellLevelsEntry const* _levels = GetSpellLevels(); + MaxLevel = _levels ? _levels->maxLevel : 0; + BaseLevel = _levels ? _levels->baseLevel : 0; + SpellLevel = _levels ? _levels->spellLevel : 0; + + // SpellPowerEntry + SpellPowerEntry const* _power = GetSpellPower(); + ManaCost = _power ? _power->manaCost : 0; + ManaCostPerlevel = _power ? _power->manaCostPerlevel : 0; + ManaCostPercentage = _power ? _power->ManaCostPercentage : 0; + ManaPerSecond = _power ? _power->manaPerSecond : 0; + + // SpellReagentsEntry + SpellReagentsEntry const* _reagents = GetSpellReagents(); + for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i) + Reagent[i] = _reagents ? _reagents->Reagent[i] : 0; + for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i) + ReagentCount[i] = _reagents ? _reagents->ReagentCount[i] : 0; + + // SpellShapeshiftEntry + SpellShapeshiftEntry const* _shapeshift = GetSpellShapeshift(); + Stances = _shapeshift ? _shapeshift->Stances : 0; + StancesNot = _shapeshift ? _shapeshift->StancesNot : 0; + + // SpellTargetRestrictionsEntry + SpellTargetRestrictionsEntry const* _target = GetSpellTargetRestrictions(); + Targets = _target ? _target->Targets : 0; + TargetCreatureType = _target ? _target->TargetCreatureType : 0; + MaxAffectedTargets = _target ? _target->MaxAffectedTargets : 0; + + // SpellTotemsEntry + SpellTotemsEntry const* _totem = GetSpellTotems(); + for (uint8 i = 0; i < 2; ++i) + TotemCategory[i] = _totem ? _totem->TotemCategory[i] : 0; + for (uint8 i = 0; i < 2; ++i) + Totem[i] = _totem ? _totem->Totem[i] : 0; ChainEntry = NULL; } @@ -1254,7 +1417,6 @@ bool SpellInfo::IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const SpellSpecificType spellSpec2 = spellInfo->GetSpellSpecific(); switch (spellSpec1) { - case SPELL_SPECIFIC_TRACKER: case SPELL_SPECIFIC_WARLOCK_ARMOR: case SPELL_SPECIFIC_MAGE_ARMOR: case SPELL_SPECIFIC_ELEMENTAL_SHIELD: @@ -1291,6 +1453,7 @@ bool SpellInfo::IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInf case SPELL_SPECIFIC_AURA: case SPELL_SPECIFIC_STING: case SPELL_SPECIFIC_CURSE: + case SPELL_SPECIFIC_BANE: case SPELL_SPECIFIC_ASPECT: case SPELL_SPECIFIC_JUDGEMENT: case SPELL_SPECIFIC_WARLOCK_CORRUPTION: @@ -1317,10 +1480,10 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const return SPELL_CAST_OK; bool actAsShifted = false; - SpellShapeshiftEntry const* shapeInfo = NULL; + SpellShapeshiftFormEntry const* shapeInfo = NULL; if (form > 0) { - shapeInfo = sSpellShapeshiftStore.LookupEntry(form); + shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form); if (!shapeInfo) { TC_LOG_ERROR("spells", "GetErrorAtShapeshiftedCast: unknown shapeshift %u", form); @@ -1472,17 +1635,27 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a } // aura limitations - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (player) { - if (!Effects[i].IsAura()) - continue; - switch (Effects[i].ApplyAuraName) + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED: - case SPELL_AURA_FLY: + if (!Effects[i].IsAura()) + continue; + + switch (Effects[i].ApplyAuraName) { - if (player && !player->IsKnowHowFlyIn(map_id, zone_id)) - return SPELL_FAILED_INCORRECT_AREA; + case SPELL_AURA_FLY: + { + if (!player->IsKnowHowFlyIn(map_id, zone_id)) + return SPELL_FAILED_INCORRECT_AREA; + break; + } + case SPELL_AURA_MOUNTED: + { + if (Effects[i].MiscValueB && !player->GetMountCapability(Effects[i].MiscValueB)) + return SPELL_FAILED_NOT_HERE; + break; + } } } } @@ -1690,8 +1863,8 @@ SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const { if (Effects[effIndex].ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) { - SpellShapeshiftEntry const* shapeShiftEntry = sSpellShapeshiftStore.LookupEntry(Effects[effIndex].MiscValue); - if (shapeShiftEntry && (shapeShiftEntry->flags1 & 1) == 0) // unk flag + SpellShapeshiftFormEntry const* shapeShiftFromEntry = sSpellShapeshiftFormStore.LookupEntry(Effects[effIndex].MiscValue); + if (shapeShiftFromEntry && (shapeShiftFromEntry->flags1 & 1) == 0) // unk flag checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED; break; } @@ -1957,6 +2130,10 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const } case SPELLFAMILY_WARLOCK: { + // Warlock (Bane of Doom | Bane of Agony | Bane of Havoc) + if (Id == 603 || Id == 980 || Id == 80240) + return SPELL_SPECIFIC_BANE; + // only warlock curses have this if (Dispel == DISPEL_CURSE) return SPELL_SPECIFIC_CURSE; @@ -1993,15 +2170,14 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const case SPELLFAMILY_PALADIN: { // Collection of all the seal family flags. No other paladin spell has any of those. - if (SpellFamilyFlags[1] & 0x26000C00 - || SpellFamilyFlags[0] & 0x0A000000) + if (SpellFamilyFlags[1] & 0xA2000800) return SPELL_SPECIFIC_SEAL; if (SpellFamilyFlags[0] & 0x00002190) return SPELL_SPECIFIC_HAND; - // Judgement of Wisdom, Judgement of Light, Judgement of Justice - if (Id == 20184 || Id == 20185 || Id == 20186) + // Judgement + if (Id == 20271) return SPELL_SPECIFIC_JUDGEMENT; // only paladin auras have this (for palaldin class family) @@ -2089,18 +2265,29 @@ int32 SpellInfo::GetMaxDuration() const return (DurationEntry->Duration[2] == -1) ? -1 : abs(DurationEntry->Duration[2]); } -uint32 SpellInfo::CalcCastTime(Spell* spell /*= NULL*/) const +uint32 SpellInfo::CalcCastTime(uint8 level, Spell* spell /*= NULL*/) const { + int32 castTime = 0; + if (!level && spell) + level = spell->GetCaster()->getLevel(); + // not all spells have cast time index and this is all is pasiive abilities - if (!CastTimeEntry) - return 0; + if (level && CastTimeMax > 0) + { + castTime = CastTimeMax; + if (CastTimeMaxLevel > level) + castTime = CastTimeMin + int32(level - 1) * (CastTimeMax - CastTimeMin) / (CastTimeMaxLevel - 1); + } + else if (CastTimeEntry) + castTime = CastTimeEntry->CastTime; - int32 castTime = CastTimeEntry->CastTime; + if (!castTime) + return 0; if (spell) spell->GetCaster()->ModSpellCastTime(this, castTime, spell); - if (Attributes & SPELL_ATTR0_REQ_AMMO && (!IsAutoRepeatRangedSpell())) + if (Attributes & SPELL_ATTR0_REQ_AMMO && (!IsAutoRepeatRangedSpell()) && !(AttributesEx9 & SPELL_ATTR9_AIMED_SHOT)) castTime += 500; return (castTime > 0) ? uint32(castTime) : 0; @@ -2170,10 +2357,9 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c case POWER_RAGE: case POWER_FOCUS: case POWER_ENERGY: - case POWER_HAPPINESS: powerCost += int32(CalculatePct(caster->GetMaxPower(Powers(PowerType)), ManaCostPercentage)); break; - case POWER_RUNE: + case POWER_RUNES: case POWER_RUNIC_POWER: TC_LOG_DEBUG("spells", "CalculateManaCost: Not implemented yet!"); break; @@ -2182,17 +2368,27 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c return 0; } } - SpellSchools school = GetFirstSchoolInMask(schoolMask); - // Flat mod from caster auras by spell school - powerCost += caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school); + + // Flat mod from caster auras by spell school and power type + Unit::AuraEffectList const& auras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL); + for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i) + { + if (!((*i)->GetMiscValue() & schoolMask)) + continue; + if (!((*i)->GetMiscValueB() & (1 << PowerType))) + continue; + powerCost += (*i)->GetAmount(); + } // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) if (AttributesEx4 & SPELL_ATTR4_SPELL_VS_EXTEND_COST) { uint32 speed = 0; +/* REVIEW - MERGE if (SpellShapeshiftEntry const* ss = sSpellShapeshiftStore.LookupEntry(caster->GetShapeshiftForm())) speed = ss->attackSpeed; else +*/ { WeaponAttackType slot = BASE_ATTACK; if (AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND) @@ -2219,8 +2415,16 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c } } - // PCT mod from user auras by school - powerCost = int32(powerCost * (1.0f + caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + school))); + // PCT mod from user auras by spell school and power type + Unit::AuraEffectList const& aurasPct = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT); + for (Unit::AuraEffectList::const_iterator i = aurasPct.begin(); i != aurasPct.end(); ++i) + { + if (!((*i)->GetMiscValue() & schoolMask)) + continue; + if (!((*i)->GetMiscValueB() & (1 << PowerType))) + continue; + powerCost += CalculatePct(powerCost, (*i)->GetAmount()); + } if (powerCost < 0) powerCost = 0; return powerCost; @@ -2275,7 +2479,8 @@ SpellInfo const* SpellInfo::GetAuraRankForLevel(uint8 level) const if (IsPositiveEffect(i) && (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA || Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || - Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID)) + Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID) && + !Effects[i].ScalingMultiplier) { needRankSelection = true; break; @@ -2366,8 +2571,6 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const case 29214: // Wrath of the Plaguebringer case 34700: // Allergic Reaction case 54836: // Wrath of the Plaguebringer - case 61987: // Avenging Wrath Marker - case 61988: // Divine Shield exclude aura return false; case 30877: // Tag Murloc case 61716: // Rabbit Costume @@ -2381,9 +2584,6 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const } break; case SPELLFAMILY_MAGE: - // Amplify Magic, Dampen Magic - if (SpellFamilyFlags[0] == 0x00002000) - return true; // Ignite if (SpellIconID == 45) return true; @@ -2399,23 +2599,11 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const break; } break; - case SPELLFAMILY_HUNTER: - // Aspect of the Viper - if (Id == 34074) - return true; - break; - case SPELLFAMILY_SHAMAN: - if (Id == 30708) - return false; - break; case SPELLFAMILY_ROGUE: switch (Id) { // Envenom must be considered as a positive effect even though it deals damage - case 32645: // Envenom (Rank 1) - case 32684: // Envenom (Rank 2) - case 57992: // Envenom (Rank 3) - case 57993: // Envenom (Rank 4) + case 32645: // Envenom return true; default: break; @@ -2642,6 +2830,81 @@ bool SpellInfo::_IsPositiveTarget(uint32 targetA, uint32 targetB) return true; } +SpellTargetRestrictionsEntry const* SpellInfo::GetSpellTargetRestrictions() const +{ + return SpellTargetRestrictionsId ? sSpellTargetRestrictionsStore.LookupEntry(SpellTargetRestrictionsId) : NULL; +} + +SpellEquippedItemsEntry const* SpellInfo::GetSpellEquippedItems() const +{ + return SpellEquippedItemsId ? sSpellEquippedItemsStore.LookupEntry(SpellEquippedItemsId) : NULL; +} + +SpellInterruptsEntry const* SpellInfo::GetSpellInterrupts() const +{ + return SpellInterruptsId ? sSpellInterruptsStore.LookupEntry(SpellInterruptsId) : NULL; +} + +SpellLevelsEntry const* SpellInfo::GetSpellLevels() const +{ + return SpellLevelsId ? sSpellLevelsStore.LookupEntry(SpellLevelsId) : NULL; +} + +SpellPowerEntry const* SpellInfo::GetSpellPower() const +{ + return SpellPowerId ? sSpellPowerStore.LookupEntry(SpellPowerId) : NULL; +} + +SpellReagentsEntry const* SpellInfo::GetSpellReagents() const +{ + return SpellReagentsId ? sSpellReagentsStore.LookupEntry(SpellReagentsId) : NULL; +} + +SpellScalingEntry const* SpellInfo::GetSpellScaling() const +{ + return SpellScalingId ? sSpellScalingStore.LookupEntry(SpellScalingId) : NULL; +} + +SpellShapeshiftEntry const* SpellInfo::GetSpellShapeshift() const +{ + return SpellShapeshiftId ? sSpellShapeshiftStore.LookupEntry(SpellShapeshiftId) : NULL; +} + +SpellTotemsEntry const* SpellInfo::GetSpellTotems() const +{ + return SpellTotemsId ? sSpellTotemsStore.LookupEntry(SpellTotemsId) : NULL; +} + +SpellAuraOptionsEntry const* SpellInfo::GetSpellAuraOptions() const +{ + return SpellAuraOptionsId ? sSpellAuraOptionsStore.LookupEntry(SpellAuraOptionsId) : NULL; +} + +SpellAuraRestrictionsEntry const* SpellInfo::GetSpellAuraRestrictions() const +{ + return SpellAuraRestrictionsId ? sSpellAuraRestrictionsStore.LookupEntry(SpellAuraRestrictionsId) : NULL; +} + +SpellCastingRequirementsEntry const* SpellInfo::GetSpellCastingRequirements() const +{ + return SpellCastingRequirementsId ? sSpellCastingRequirementsStore.LookupEntry(SpellCastingRequirementsId) : NULL; +} + +SpellCategoriesEntry const* SpellInfo::GetSpellCategories() const +{ + return SpellCategoriesId ? sSpellCategoriesStore.LookupEntry(SpellCategoriesId) : NULL; +} + +SpellClassOptionsEntry const* SpellInfo::GetSpellClassOptions() const +{ + return SpellClassOptionsId ? sSpellClassOptionsStore.LookupEntry(SpellClassOptionsId) : NULL; +} + +SpellCooldownsEntry const* SpellInfo::GetSpellCooldowns() const +{ + return SpellCooldownsId ? sSpellCooldownsStore.LookupEntry(SpellCooldownsId) : NULL; +} + void SpellInfo::_UnloadImplicitTargetConditionLists() { // find the same instances of ConditionList and delete them. diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 562e0371fe1..ea29eb1b00f 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -29,6 +29,7 @@ class Player; class Item; class Spell; class SpellInfo; +class WorldObject; struct SpellChainNode; struct SpellTargetPosition; struct SpellDurationEntry; @@ -61,7 +62,7 @@ enum SpellCastTargetFlags TARGET_FLAG_UNIT_MINIPET = 0x00010000, // pguid, used to validate target (if non combat pet) TARGET_FLAG_GLYPH_SLOT = 0x00020000, // used in glyph spells TARGET_FLAG_DEST_TARGET = 0x00040000, // sometimes appears with DEST_TARGET spells (may appear or not for a given spell) - TARGET_FLAG_UNUSED20 = 0x00080000, // uint32 counter, loop { vec3 - screen position (?), guid }, not used so far + TARGET_FLAG_EXTRA_TARGETS = 0x00080000, // uint32 counter, loop { vec3 - screen position (?), guid }, not used so far TARGET_FLAG_UNIT_PASSENGER = 0x00100000, // guessed, used to validate target (if vehicle passenger) TARGET_FLAG_UNIT_MASK = TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY @@ -166,7 +167,9 @@ enum SpellSpecificType SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE = 25, SPELL_SPECIFIC_WARRIOR_ENRAGE = 26, SPELL_SPECIFIC_PRIEST_DIVINE_SPIRIT = 27, - SPELL_SPECIFIC_HAND = 28 + SPELL_SPECIFIC_HAND = 28, + SPELL_SPECIFIC_PHASE = 29, + SPELL_SPECIFIC_BANE = 30 }; enum SpellCustomAttributes @@ -244,17 +247,22 @@ public: SpellImplicitTargetInfo TargetA; SpellImplicitTargetInfo TargetB; SpellRadiusEntry const* RadiusEntry; + SpellRadiusEntry const* MaxRadiusEntry; uint32 ChainTarget; uint32 ItemType; uint32 TriggerSpell; flag96 SpellClassMask; std::list<Condition*>* ImplicitTargetConditions; + // SpellScalingEntry + float ScalingMultiplier; + float DeltaScalingMultiplier; + float ComboScalingMultiplier; SpellEffectInfo() : _spellInfo(NULL), _effIndex(0), Effect(0), ApplyAuraName(0), Amplitude(0), DieSides(0), RealPointsPerLevel(0), BasePoints(0), PointsPerComboPoint(0), ValueMultiplier(0), DamageMultiplier(0), BonusMultiplier(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), RadiusEntry(NULL), ChainTarget(0), ItemType(0), TriggerSpell(0), ImplicitTargetConditions(NULL) {} - SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex); + SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex, SpellEffectEntry const* effect); bool IsEffect() const; bool IsEffect(SpellEffects effectName) const; @@ -272,6 +280,7 @@ public: float CalcDamageMultiplier(Unit* caster, Spell* spell = NULL) const; bool HasRadius() const; + bool HasMaxRadius() const; float CalcRadius(Unit* caster = NULL, Spell* = NULL) const; uint32 GetProvidedTargetMask() const; @@ -304,6 +313,9 @@ public: uint32 AttributesEx5; uint32 AttributesEx6; uint32 AttributesEx7; + uint32 AttributesEx8; + uint32 AttributesEx9; + uint32 AttributesEx10; uint32 AttributesCu; uint32 Stances; uint32 StancesNot; @@ -338,7 +350,6 @@ public: uint32 ManaCost; uint32 ManaCostPerlevel; uint32 ManaPerSecond; - uint32 ManaPerSecondPerLevel; uint32 ManaCostPercentage; uint32 RuneCostID; SpellRangeEntry const* RangeEntry; @@ -354,8 +365,8 @@ public: uint32 SpellVisual[2]; uint32 SpellIconID; uint32 ActiveIconID; - char* SpellName[16]; - char* Rank[16]; + char* SpellName; + char* Rank; uint32 MaxTargetLevel; uint32 MaxAffectedTargets; uint32 SpellFamilyName; @@ -364,11 +375,51 @@ public: uint32 PreventionType; int32 AreaGroupId; uint32 SchoolMask; + uint32 SpellDifficultyId; + uint32 SpellScalingId; + uint32 SpellAuraOptionsId; + uint32 SpellAuraRestrictionsId; + uint32 SpellCastingRequirementsId; + uint32 SpellCategoriesId; + uint32 SpellClassOptionsId; + uint32 SpellCooldownsId; + uint32 SpellEquippedItemsId; + uint32 SpellInterruptsId; + uint32 SpellLevelsId; + uint32 SpellPowerId; + uint32 SpellReagentsId; + uint32 SpellShapeshiftId; + uint32 SpellTargetRestrictionsId; + uint32 SpellTotemsId; + // SpellScalingEntry + int32 CastTimeMin; + int32 CastTimeMax; + int32 CastTimeMaxLevel; + int32 ScalingClass; + float CoefBase; + int32 CoefLevelBase; SpellEffectInfo Effects[MAX_SPELL_EFFECTS]; uint32 ExplicitTargetMask; SpellChainNode const* ChainEntry; - SpellInfo(SpellEntry const* spellEntry); + // struct access functions + SpellTargetRestrictionsEntry const* GetSpellTargetRestrictions() const; + SpellAuraOptionsEntry const* GetSpellAuraOptions() const; + SpellAuraRestrictionsEntry const* GetSpellAuraRestrictions() const; + SpellCastingRequirementsEntry const* GetSpellCastingRequirements() const; + SpellCategoriesEntry const* GetSpellCategories() const; + SpellClassOptionsEntry const* GetSpellClassOptions() const; + SpellCooldownsEntry const* GetSpellCooldowns() const; + SpellEquippedItemsEntry const* GetSpellEquippedItems() const; + SpellInterruptsEntry const* GetSpellInterrupts() const; + SpellLevelsEntry const* GetSpellLevels() const; + SpellPowerEntry const* GetSpellPower() const; + SpellReagentsEntry const* GetSpellReagents() const; + SpellScalingEntry const* GetSpellScaling() const; + SpellShapeshiftEntry const* GetSpellShapeshift() const; + SpellTotemsEntry const* GetSpellTotems() const; + + SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effects); ~SpellInfo(); uint32 GetCategory() const; @@ -448,7 +499,7 @@ public: uint32 GetMaxTicks() const; - uint32 CalcCastTime(Spell* spell = NULL) const; + uint32 CalcCastTime(uint8 level = 0, Spell* spell = NULL) const; uint32 GetRecoveryTime() const; int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index bc97744fe32..0e5264bf56a 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -35,13 +35,13 @@ bool IsPrimaryProfessionSkill(uint32 skill) { SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill); - if (!pSkill) - return false; - - if (pSkill->categoryId != SKILL_CATEGORY_PROFESSION) - return false; + return pSkill && pSkill->categoryId == SKILL_CATEGORY_PROFESSION; +} - return true; +bool IsWeaponSkill(uint32 skill) +{ + SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill); + return pSkill && pSkill->categoryId == SKILL_CATEGORY_WEAPON; } bool IsPartOfSkillLine(uint32 skillId, uint32 spellId) @@ -127,6 +127,9 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, // Seduction else if (spellproto->SpellFamilyFlags[1] & 0x10000000) return DIMINISHING_FEAR; + // Sin and Punishment (Priest spell, don't ask) + else if (spellproto->SpellIconID == 1869) + return DIMINISHING_NONE; break; } case SPELLFAMILY_DRUID: @@ -293,7 +296,7 @@ int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const return 6 * IN_MILLISECONDS; // Hunter's Mark if (spellproto->SpellFamilyFlags[0] & 0x400) - return 120 * IN_MILLISECONDS; + return 30 * IN_MILLISECONDS; break; } case SPELLFAMILY_PALADIN: @@ -320,7 +323,7 @@ int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const break; } - return 10 * IN_MILLISECONDS; + return 8 * IN_MILLISECONDS; } bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group) @@ -1153,19 +1156,7 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 // Extra conditions switch (spellId) { - case 58600: // No fly Zone - Dalaran - { - if (!player) - return false; - - AreaTableEntry const* pArea = GetAreaEntryByAreaID(player->GetAreaId()); - if (!(pArea && pArea->flags & AREA_FLAG_NO_FLY_ZONE)) - return false; - if (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY)) - return false; - break; - } - case 58730: // No fly Zone - Wintergrasp + case 91604: // No fly Zone - Wintergrasp { if (!player) return false; @@ -1522,10 +1513,10 @@ void SpellMgr::LoadSpellLearnSpells() { Field* fields = result->Fetch(); - uint32 spell_id = fields[0].GetUInt16(); + uint32 spell_id = fields[0].GetUInt32(); SpellLearnSpellNode node; - node.spell = fields[1].GetUInt16(); + node.spell = fields[1].GetUInt32(); node.active = fields[2].GetBool(); node.autoLearned = false; @@ -1552,6 +1543,9 @@ void SpellMgr::LoadSpellLearnSpells() ++count; } while (result->NextRow()); + // copy state loaded from db + SpellLearnSpellMap dbSpellLearnSpells = mSpellLearnSpells; + // search auto-learned spells and add its to map also for use in unlearn spells/talents uint32 dbc_count = 0; for (uint32 spell = 0; spell < GetSpellInfoStoreSize(); ++spell) @@ -1578,7 +1572,7 @@ void SpellMgr::LoadSpellLearnSpells() // other required explicit dependent learning dbc_node.autoLearned = entry->Effects[i].TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentSpellCost(spell) > 0 || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP); - SpellLearnSpellMapBounds db_node_bounds = GetSpellLearnSpellMapBounds(spell); + SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spell); bool found = false; for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr) @@ -1601,7 +1595,68 @@ void SpellMgr::LoadSpellLearnSpells() } } - TC_LOG_INFO("server.loading", ">> Loaded %u spell learn spells + %u found in DBC in %u ms", count, dbc_count, GetMSTimeDiffToNow(oldMSTime)); + uint32 mastery_count = 0; + for (uint32 i = 0; i < sTalentTabStore.GetNumRows(); ++i) + { + TalentTabEntry const* talentTab = sTalentTabStore.LookupEntry(i); + if (!talentTab) + continue; + + for (uint32 c = CLASS_WARRIOR; c < MAX_CLASSES; ++c) + { + if (!(talentTab->ClassMask & (1 << (c - 1)))) + continue; + + uint32 masteryMainSpell = MasterySpells[c]; + + for (uint32 m = 0; m < MAX_MASTERY_SPELLS; ++m) + { + uint32 mastery = talentTab->MasterySpellId[m]; + if (!mastery) + continue; + + SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(masteryMainSpell); + bool found = false; + for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr) + { + if (itr->second.spell == mastery) + { + TC_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically as mastery learned spell from TalentTab.dbc", masteryMainSpell, mastery); + found = true; + break; + } + } + + if (found) + continue; + + // Check if it is already found in Spell.dbc, ignore silently if yes + SpellLearnSpellMapBounds dbc_node_bounds = GetSpellLearnSpellMapBounds(masteryMainSpell); + found = false; + for (SpellLearnSpellMap::const_iterator itr = dbc_node_bounds.first; itr != dbc_node_bounds.second; ++itr) + { + if (itr->second.spell == mastery) + { + found = true; + break; + } + } + + if (found) + continue; + + SpellLearnSpellNode masteryNode; + masteryNode.spell = mastery; + masteryNode.active = true; + masteryNode.autoLearned = false; + + mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(masteryMainSpell, masteryNode)); + ++mastery_count; + } + } + } + + TC_LOG_INFO("server.loading", ">> Loaded %u spell learn spells, %u found in Spell.dbc and %u from TalentTab.dbc in %u ms", count, dbc_count, mastery_count, GetMSTimeDiffToNow(oldMSTime)); } void SpellMgr::LoadSpellTargetPositions() @@ -2719,6 +2774,19 @@ void SpellMgr::LoadSpellAreas() TC_LOG_INFO("server.loading", ">> Loaded %u spell area requirements in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +// Temporary structure to hold spell effect entries for faster loading +struct SpellEffectArray +{ + SpellEffectArray() + { + effects[0] = NULL; + effects[1] = NULL; + effects[2] = NULL; + } + + SpellEffectEntry const* effects[MAX_SPELL_EFFECTS]; +}; + void SpellMgr::LoadSpellInfoStore() { uint32 oldMSTime = getMSTime(); @@ -2726,9 +2794,20 @@ void SpellMgr::LoadSpellInfoStore() UnloadSpellInfoStore(); mSpellInfoMap.resize(sSpellStore.GetNumRows(), NULL); + std::map<uint32, SpellEffectArray> effectsBySpell; + + for (uint32 i = 0; i < sSpellEffectStore.GetNumRows(); ++i) + { + SpellEffectEntry const* effect = sSpellEffectStore.LookupEntry(i); + if (!effect) + continue; + + effectsBySpell[effect->EffectSpellId].effects[effect->EffectIndex] = effect; + } + for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(i)) - mSpellInfoMap[i] = new SpellInfo(spellEntry); + mSpellInfoMap[i] = new SpellInfo(spellEntry, effectsBySpell[i].effects); TC_LOG_INFO("server.loading", ">> Loaded SpellInfo store in %u ms", GetMSTimeDiffToNow(oldMSTime)); } @@ -2923,7 +3002,7 @@ void SpellMgr::LoadSpellInfoCorrections() SpellInfo* spellInfo = NULL; for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { - spellInfo = mSpellInfoMap[i]; + spellInfo = (SpellInfo*)mSpellInfoMap[i]; if (!spellInfo) continue; @@ -2947,9 +3026,6 @@ void SpellMgr::LoadSpellInfoCorrections() switch (spellInfo->Id) { - case 53096: // Quetz'lun's Judgment - spellInfo->MaxAffectedTargets = 1; - break; case 42436: // Drink! (Brewfest) spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); break; @@ -2974,7 +3050,6 @@ void SpellMgr::LoadSpellInfoCorrections() case 63665: // Charge (Argent Tournament emote on riders) case 31298: // Sleep (needs target selection script) case 51904: // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed) - case 2895: // Wrath of Air Totem rank 1 (Aura) case 68933: // Wrath of Air Totem rank 2 (Aura) case 29200: // Purify Helboar Meat spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); @@ -3003,28 +3078,13 @@ void SpellMgr::LoadSpellInfoCorrections() case 59372: // Energize Cores spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENEMY); break; - case 8494: // Mana Shield (rank 2) - // because of bug in dbc - spellInfo->ProcChance = 0; - break; - case 20335: // Heart of the Crusader - case 20336: - case 20337: + case 63320: // Glyph of Life Tap case 53228: // Rapid Killing (Rank 1) case 53232: // Rapid Killing (Rank 2) - case 63320: // Glyph of Life Tap // Entries were not updated after spell effect change, we have to do that manually :/ spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; break; - case 5308: // Execute (Rank 1) - case 20658: // Execute (Rank 2) - case 20660: // Execute (Rank 3) - case 20661: // Execute (Rank 4) - case 20662: // Execute (Rank 5) - case 25234: // Execute (Rank 6) - case 25236: // Execute (Rank 7) - case 47470: // Execute (Rank 8) - case 47471: // Execute (Rank 9) + case 5308: // Execute spellInfo->AttributesEx3 |= SPELL_ATTR3_CANT_TRIGGER_PROC; break; case 59725: // Improved Spell Reflection - aoe aura @@ -3032,47 +3092,47 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY); spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS_2); break; - case 44978: // Wild Magic - case 45001: - case 45002: - case 45004: - case 45006: - case 45010: case 31347: // Doom + case 36327: // Shoot Arcane Explosion Arrow + case 39365: // Thundering Storm + case 41071: // Raise Dead (HACK) + case 42442: // Vengeance Landing Cannonfire + case 42611: // Shoot + case 44978: // Wild Magic + case 45001: // Wild Magic + case 45002: // Wild Magic + case 45004: // Wild Magic + case 45006: // Wild Magic + case 45010: // Wild Magic + case 45761: // Shoot Gun + case 45863: // Cosmetic - Incinerate to Random Target + case 48246: // Ball of Flame case 41635: // Prayer of Mending case 44869: // Spectral Blast case 45027: // Revitalize case 45976: // Muru Portal Channel - case 39365: // Thundering Storm - case 41071: // Raise Dead (HACK) case 52124: // Sky Darkener Assault - case 42442: // Vengeance Landing Cannonfire - case 45863: // Cosmetic - Incinerate to Random Target - case 25425: // Shoot - case 45761: // Shoot - case 42611: // Shoot - case 61588: // Blazing Harpoon + case 53096: // Quetz'lun's Judgment case 52479: // Gift of the Harvester - case 48246: // Ball of Flame - case 36327: // Shoot Arcane Explosion Arrow + case 61588: // Blazing Harpoon spellInfo->MaxAffectedTargets = 1; break; case 36384: // Skartax Purple Beam spellInfo->MaxAffectedTargets = 2; break; - case 41376: // Spite - case 39992: // Needle Spine + case 28542: // Life Drain - Sapphiron + case 29213: // Curse of the Plaguebringer - Noth case 29576: // Multi-Shot - case 40816: // Saber Lash case 37790: // Spread Shot - case 46771: // Flame Sear - case 45248: // Shadow Blades + case 39992: // Needle Spine + case 40816: // Saber Lash case 41303: // Soul Drain + case 41376: // Spite + case 45248: // Shadow Blades + case 46771: // Flame Sear + case 54171: // Divine Storm case 54172: // Divine Storm (heal) - case 29213: // Curse of the Plaguebringer - Noth - case 28542: // Life Drain - Sapphiron case 66588: // Flaming Spear - case 54171: // Divine Storm spellInfo->MaxAffectedTargets = 3; break; case 38310: // Multi-Shot @@ -3100,23 +3160,20 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->MaxAffectedTargets = 15; break; case 33711: // Murmur's Touch - case 38794: + case 38794: // Murmur's Touch spellInfo->MaxAffectedTargets = 1; spellInfo->Effects[EFFECT_0].TriggerSpell = 33760; break; case 17941: // Shadow Trance case 22008: // Netherwind Focus - case 31834: // Light's Grace - case 34754: // Clearcasting + case 34477: // Misdirection case 34936: // Backlash case 48108: // Hot Streak case 51124: // Killing Machine case 54741: // Firestarter case 57761: // Fireball! - case 39805: // Lightning Overload case 64823: // Item - Druid T8 Balance 4P Bonus - case 34477: // Misdirection - case 44401: // Missile Barrage + case 88819: // Daybreak spellInfo->ProcCharges = 1; break; case 44544: // Fingers of Frost @@ -3129,36 +3186,34 @@ void SpellMgr::LoadSpellInfoCorrections() case 28200: // Ascendance (Talisman of Ascendance trinket) spellInfo->ProcCharges = 6; break; - case 37408: // Oscillation Field - spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; - break; - case 47201: // Everlasting Affliction - case 47202: - case 47203: - case 47204: - case 47205: + case 47201: // Everlasting Affliction (1) + case 47202: // Everlasting Affliction (2) + case 47203: // Everlasting Affliction (3) + case 47204: // Everlasting Affliction (4) + case 47205: // Everlasting Affliction (5) // add corruption to affected spells spellInfo->Effects[EFFECT_1].SpellClassMask[0] |= 2; break; + case 37408: // Oscillation Field + spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; + break; case 51852: // The Eye of Acherus (no spawn in phase 2 in db) spellInfo->Effects[EFFECT_0].MiscValue |= 1; break; case 51912: // Crafty's Ultra-Advanced Proto-Typical Shortening Blaster spellInfo->Effects[EFFECT_0].Amplitude = 3000; break; - case 29809: // Desecration Arm - 36 instead of 37 - typo? :/ - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_7_YARDS); - break; // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data // To prevent aura staying on target after talent unlearned - case 48420: + case 48420: // Master Shapeshifter + case 24900: // Heart of the Wild - Cat Effect spellInfo->Stances = 1 << (FORM_CAT - 1); break; - case 48421: - spellInfo->Stances = 1 << (FORM_MOONKIN - 1); + case 24899: // Heart of the Wild - Bear Effect + spellInfo->Stances = 1 << (FORM_BEAR - 1); break; - case 48422: - spellInfo->Stances = 1 << (FORM_TREE - 1); + case 48421: // Master Shapeshifter + spellInfo->Stances = 1 << (FORM_MOONKIN - 1); break; case 51466: // Elemental Oath (Rank 1) case 51470: // Elemental Oath (Rank 2) @@ -3174,23 +3229,9 @@ void SpellMgr::LoadSpellInfoCorrections() case 64904: // Hymn of Hope spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT; break; - case 19465: // Improved Stings (Rank 2) - spellInfo->Effects[EFFECT_2].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); - break; case 30421: // Nether Portal - Perseverence spellInfo->Effects[EFFECT_2].BasePoints += 30000; break; - case 16834: // Natural shapeshifter - case 16835: - spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21); - break; - case 51735: // Ebon Plague - case 51734: - case 51726: - spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; - spellInfo->SpellFamilyFlags[2] = 0x10; - spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN; - break; case 41913: // Parasitic Shadowfiend Passive spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_DUMMY; // proc debuff, and summon infinite fiends break; @@ -3200,7 +3241,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 27915: // Anchor to Skulls case 27931: // Anchor to Skulls case 27937: // Anchor to Skulls - spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); + spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(EFFECT_RADIUS_10_YARDS); break; // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target // this is the only known exception, probably just wrong data @@ -3209,10 +3250,6 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY); spellInfo->Effects[EFFECT_1].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY); break; - case 57994: // Wind Shear - improper data for EFFECT_1 in 3.3.5 DBC, but is correct in 4.x - spellInfo->Effects[EFFECT_1].Effect = SPELL_EFFECT_MODIFY_THREAT_PERCENT; - spellInfo->Effects[EFFECT_1].BasePoints = -6; // -5% - break; case 63675: // Improved Devouring Plague spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; break; @@ -3223,26 +3260,16 @@ void SpellMgr::LoadSpellInfoCorrections() case 6474: // Earthbind Totem (instant pulse) spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY; break; - case 52109: // Flametongue Totem rank 1 (Aura) - case 52110: // Flametongue Totem rank 2 (Aura) - case 52111: // Flametongue Totem rank 3 (Aura) - case 52112: // Flametongue Totem rank 4 (Aura) - case 52113: // Flametongue Totem rank 5 (Aura) - case 58651: // Flametongue Totem rank 6 (Aura) - case 58654: // Flametongue Totem rank 7 (Aura) - case 58655: // Flametongue Totem rank 8 (Aura) - spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); - spellInfo->Effects[EFFECT_1].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); - spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(); - spellInfo->Effects[EFFECT_1].TargetB = SpellImplicitTargetInfo(); - break; case 53241: // Marked for Death (Rank 1) case 53243: // Marked for Death (Rank 2) - case 53244: // Marked for Death (Rank 3) - case 53245: // Marked for Death (Rank 4) - case 53246: // Marked for Death (Rank 5) spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(0x00067801, 0x10820001, 0x00000801); break; + case 5176: // Wrath + case 2912: // Starfire + case 78674: // Starsurge + spellInfo->Effects[EFFECT_1].Effect = SPELL_EFFECT_DUMMY; + spellInfo->Effects[EFFECT_1].TargetA = TARGET_UNIT_CASTER; + break; case 70728: // Exploit Weakness (needs target selection script) case 70840: // Devious Minds (needs target selection script) spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); @@ -3277,26 +3304,9 @@ void SpellMgr::LoadSpellInfoCorrections() case 45602: // Ride Carpet spellInfo->Effects[EFFECT_0].BasePoints = 0; // force seat 0, vehicle doesn't have the required seat flags for "no seat specified (-1)" break; - case 64745: // Item - Death Knight T8 Tank 4P Bonus - case 64936: // Item - Warrior T8 Protection 4P Bonus - spellInfo->Effects[EFFECT_0].BasePoints = 100; // 100% chance of procc'ing, not -10% (chance calculated in PrepareTriggersExecutedOnHit) - break; - case 19970: // Entangling Roots (Rank 6) -- Nature's Grasp Proc - case 19971: // Entangling Roots (Rank 5) -- Nature's Grasp Proc - case 19972: // Entangling Roots (Rank 4) -- Nature's Grasp Proc - case 19973: // Entangling Roots (Rank 3) -- Nature's Grasp Proc - case 19974: // Entangling Roots (Rank 2) -- Nature's Grasp Proc - case 19975: // Entangling Roots (Rank 1) -- Nature's Grasp Proc - case 27010: // Entangling Roots (Rank 7) -- Nature's Grasp Proc - case 53313: // Entangling Roots (Rank 8) -- Nature's Grasp Proc - spellInfo->CastTimeEntry = sSpellCastTimesStore.LookupEntry(1); - break; case 61719: // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE; break; - case 70650: // Death Knight T10 Tank 2P Bonus - spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_ADD_PCT_MODIFIER; - break; case 71838: // Drain Life - Bryntroll Normal case 71839: // Drain Life - Bryntroll Heroic spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT; @@ -3376,7 +3386,7 @@ void SpellMgr::LoadSpellInfoCorrections() case 64031: // Scrapyard Teleport case 64032: // Formation Grounds Teleport case 65042: // Prison of Yogg-Saron Teleport - spellInfo->Effects[0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); + spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); break; // ENDOF ULDUAR SPELLS // @@ -3419,10 +3429,6 @@ void SpellMgr::LoadSpellInfoCorrections() case 70861: // Sindragosa's Lair Teleport spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); break; - case 69055: // Bone Slice (Lord Marrowgar) - case 70814: // Bone Slice (Lord Marrowgar) - spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_5_YARDS); // 5yd - break; case 69075: // Bone Storm (Lord Marrowgar) case 70834: // Bone Storm (Lord Marrowgar) case 70835: // Bone Storm (Lord Marrowgar) @@ -3665,39 +3671,46 @@ void SpellMgr::LoadSpellInfoCorrections() break; // ENDOF EYE OF ETERNITY SPELLS // - // OCULUS SPELLS - // The spells below are here because their effect 1 is giving warning due to - // triggered spell not found in any dbc and is missing from encounter source* of data. - // Even judged as clientside these spells can't be guessed for* now. - case 49462: // Call Ruby Drake - case 49461: // Call Amber Drake - case 49345: // Call Emerald Drake - spellInfo->Effects[EFFECT_1].Effect = 0; - break; - // ENDOF OCULUS SPELLS - // case 40055: // Introspection case 40165: // Introspection case 40166: // Introspection case 40167: // Introspection spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1; break; - case 45524: // Chains of Ice - spellInfo->Effects[EFFECT_2].TargetA = SpellImplicitTargetInfo(); - break; case 2378: // Minor Fortitude spellInfo->ManaCost = 0; spellInfo->ManaPerSecond = 0; break; + // Halls Of Origination spells + // Temple Guardian Anhuur + case 76606: // Disable Beacon Beams L + case 76608: // Disable Beacon Beams R + // Little hack, Increase the radius so it can hit the Cave In Stalkers in the platform. + spellInfo->Effects[EFFECT_0].MaxRadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_45_YARDS); + break; + case 75323: // Reverberating Hymn + // Aura is refreshed at 3 seconds, and the tick should happen at the fourth. + spellInfo->AttributesEx8 |= SPELL_ATTR8_DONT_RESET_PERIODIC_TIMER; + break; case 24314: // Threatening Gaze spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_JUMP; break; + case 5420: // Tree of Life (Passive) + spellInfo->Stances = 1 << (FORM_TREE - 1); + break; + case 49376: // Feral Charge (Cat Form) + spellInfo->AttributesEx3 &= ~SPELL_ATTR3_CANT_TRIGGER_PROC; + break; case 45257: // Using Steam Tonk Controller case 45440: // Steam Tonk Controller case 60256: // Collect Sample // Crashes client on pressing ESC spellInfo->AttributesEx4 &= ~SPELL_ATTR4_TRIGGERED; break; + case 96942: // Gaze of Occu'thar + case 101009: // Gaze of Occu'thar + spellInfo->AttributesEx &= ~SPELL_ATTR1_CHANNELED_1; + break; // ISLE OF CONQUEST SPELLS // case 66551: // Teleport diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 448ddb9860b..f2555820b92 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -55,42 +55,40 @@ enum SpellFamilyFlag // SPELLFAMILYFLAG2 = SpellFamilyFlags[2] // Rogue - SPELLFAMILYFLAG_ROGUE_VANISH = 0x00000800, - SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT = 0x00000860, // Vanish, Evasion, Sprint - SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP = 0x00000240, // Cold Blood, Shadowstep - SPELLFAMILYFLAG_ROGUE_KICK = 0x00000010, // Kick - SPELLFAMILYFLAG1_ROGUE_DISMANTLE = 0x00100000, // Dismantle - SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY = 0x40000000, // Blade Flurry - SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY = 0x00000800, // Blade Flurry + SPELLFAMILYFLAG0_ROGUE_VANISH = 0x00000800, + SPELLFAMILYFLAG0_ROGUE_VAN_SPRINT = 0x00000840, // Vanish, Sprint + SPELLFAMILYFLAG1_ROGUE_SHADOWSTEP = 0x00000200, // Shadowstep + SPELLFAMILYFLAG0_ROGUE_KICK = 0x00000010, // Kick + SPELLFAMILYFLAG1_ROGUE_DISMANTLE_SMOKE_BOMB = 0x80100000, // Dismantle, Smoke Bomb // Warrior - SPELLFAMILYFLAG_WARRIOR_CHARGE = 0x00000001, - SPELLFAMILYFLAG_WARRIOR_SLAM = 0x00200000, - SPELLFAMILYFLAG_WARRIOR_EXECUTE = 0x20000000, - SPELLFAMILYFLAG_WARRIOR_CONCUSSION_BLOW = 0x04000000, + SPELLFAMILYFLAG_WARRIOR_CHARGE = 0x00000001, + SPELLFAMILYFLAG_WARRIOR_SLAM = 0x00200000, + SPELLFAMILYFLAG_WARRIOR_EXECUTE = 0x20000000, + SPELLFAMILYFLAG_WARRIOR_CONCUSSION_BLOW = 0x04000000, // Warlock - SPELLFAMILYFLAG_WARLOCK_LIFETAP = 0x00040000, + SPELLFAMILYFLAG_WARLOCK_LIFETAP = 0x00040000, // Druid - SPELLFAMILYFLAG2_DRUID_STARFALL = 0x00000100, + SPELLFAMILYFLAG2_DRUID_STARFALL = 0x00000100, // Paladin - SPELLFAMILYFLAG1_PALADIN_DIVINESTORM = 0x00020000, + SPELLFAMILYFLAG1_PALADIN_DIVINESTORM = 0x00020000, // Shaman - SPELLFAMILYFLAG_SHAMAN_FROST_SHOCK = 0x80000000, - SPELLFAMILYFLAG_SHAMAN_HEALING_STREAM = 0x00002000, - SPELLFAMILYFLAG_SHAMAN_MANA_SPRING = 0x00004000, - SPELLFAMILYFLAG2_SHAMAN_LAVA_LASH = 0x00000004, - SPELLFAMILYFLAG_SHAMAN_FIRE_NOVA = 0x28000000, + SPELLFAMILYFLAG_SHAMAN_FROST_SHOCK = 0x80000000, + SPELLFAMILYFLAG_SHAMAN_HEALING_STREAM = 0x00002000, + SPELLFAMILYFLAG_SHAMAN_MANA_SPRING = 0x00004000, + SPELLFAMILYFLAG2_SHAMAN_LAVA_LASH = 0x00000004, + SPELLFAMILYFLAG_SHAMAN_FIRE_NOVA = 0x28000000, // Deathknight - SPELLFAMILYFLAG_DK_DEATH_STRIKE = 0x00000010, - SPELLFAMILYFLAG_DK_DEATH_COIL = 0x00002000, + SPELLFAMILYFLAG_DK_DEATH_STRIKE = 0x00000010, + SPELLFAMILYFLAG_DK_DEATH_COIL = 0x00002000, /// @todo Figure out a more accurate name for the following familyflag(s) - SPELLFAMILYFLAG_SHAMAN_TOTEM_EFFECTS = 0x04000000 // Seems to be linked to most totems and some totem effects + SPELLFAMILYFLAG_SHAMAN_TOTEM_EFFECTS = 0x04000000 // Seems to be linked to most totems and some totem effects }; @@ -580,6 +578,8 @@ typedef std::map<int32, std::vector<int32> > SpellLinkedMap; bool IsPrimaryProfessionSkill(uint32 skill); +bool IsWeaponSkill(uint32 skill); + inline bool IsProfessionSkill(uint32 skill) { return IsPrimaryProfessionSkill(skill) || skill == SKILL_FISHING || skill == SKILL_COOKING || skill == SKILL_FIRST_AID; diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 8bd7a5a5e71..3fbbd34777b 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -327,6 +327,7 @@ void CreatureTextMgr::SendSound(Creature* source, uint32 sound, ChatMsg msgType, WorldPacket data(SMSG_PLAY_SOUND, 4); data << uint32(sound); + data << uint64(source->GetGUID()); SendNonChatPacket(source, &data, msgType, whisperTarget, range, team, gmOnly); } diff --git a/src/server/game/Texts/CreatureTextMgr.h b/src/server/game/Texts/CreatureTextMgr.h index 18dc7683b8d..aef38a1923e 100644 --- a/src/server/game/Texts/CreatureTextMgr.h +++ b/src/server/game/Texts/CreatureTextMgr.h @@ -151,7 +151,7 @@ class CreatureTextLocalizer { messageTemplate = new WorldPacket(); whisperGUIDpos = _builder(messageTemplate, loc_idx); - ASSERT(messageTemplate->GetOpcode() != MSG_NULL_ACTION); + ASSERT(messageTemplate->GetOpcode() != NULL_OPCODE); _packetCache[loc_idx] = new std::pair<WorldPacket*, size_t>(messageTemplate, whisperGUIDpos); } else diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp index 71d51153b4c..c6b1da46e6b 100644 --- a/src/server/game/Tickets/TicketMgr.cpp +++ b/src/server/game/Tickets/TicketMgr.cpp @@ -125,6 +125,11 @@ void GmTicket::WritePacket(WorldPacket& data) const data << uint8(std::min(_escalatedStatus, TICKET_IN_ESCALATION_QUEUE)); // escalated data data << uint8(_viewed ? GMTICKET_OPENEDBYGM_STATUS_OPENED : GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED); // whether or not it has been viewed + + // TODO: implement these + std::string waitTimeOverrideMessage = ""; + data << waitTimeOverrideMessage; + data << uint32(0); // waitTimeOverrideMinutes } void GmTicket::SendResponse(WorldSession* session) const diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 6cec8ba0220..3cde5a6d70f 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -24,7 +24,7 @@ #include "AccountMgr.h" #include "World.h" -#define DUMP_TABLE_COUNT 27 +#define DUMP_TABLE_COUNT 29 struct DumpTable { char const* name; @@ -39,6 +39,8 @@ static DumpTable dumpTables[DUMP_TABLE_COUNT] = { "character_achievement_progress", DTT_CHAR_TABLE }, { "character_action", DTT_CHAR_TABLE }, { "character_aura", DTT_CHAR_TABLE }, + { "character_currency", DTT_CHAR_TABLE }, + { "character_cuf_profiles", DTT_CHAR_TABLE }, { "character_declinedname", DTT_CHAR_TABLE }, { "character_equipmentsets", DTT_EQSET_TABLE}, { "character_glyphs", DTT_CHAR_TABLE }, @@ -320,10 +322,13 @@ bool PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tabl break; case DTT_CHARACTER: { - if (result->GetFieldCount() <= 68) // avoid crashes on next check + if (result->GetFieldCount() <= 64) // avoid crashes on next check + { TC_LOG_FATAL("misc", "PlayerDumpWriter::DumpTable - Trying to access non-existing or wrong positioned field (`deleteInfos_Account`) in `characters` table."); + return false; + } - if (result->Fetch()[68].GetUInt32()) // characters.deleteInfos_Account - if filled error + if (result->Fetch()[64].GetUInt32()) // characters.deleteInfos_Account - if filled error return false; break; } @@ -543,18 +548,18 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) - if (!changenth(line, 37, "1")) // characters.at_login set to "rename on login" + if (!changenth(line, 38, "1")) // characters.at_login set to "rename on login" ROLLBACK(DUMP_FILE_BROKEN); } else if (!changenth(line, 3, name.c_str())) // characters.name ROLLBACK(DUMP_FILE_BROKEN); const char null[5] = "NULL"; - if (!changenth(line, 69, null)) // characters.deleteInfos_Account + if (!changenth(line, 63, null)) // characters.deleteInfos_Account ROLLBACK(DUMP_FILE_BROKEN); - if (!changenth(line, 70, null)) // characters.deleteInfos_Name + if (!changenth(line, 64, null)) // characters.deleteInfos_Name ROLLBACK(DUMP_FILE_BROKEN); - if (!changenth(line, 71, null)) // characters.deleteDate + if (!changenth(line, 65, null)) // characters.deleteDate ROLLBACK(DUMP_FILE_BROKEN); break; } diff --git a/src/server/game/Tools/PlayerDump.h b/src/server/game/Tools/PlayerDump.h index ece2c0693e2..8be71f1a819 100644 --- a/src/server/game/Tools/PlayerDump.h +++ b/src/server/game/Tools/PlayerDump.h @@ -30,7 +30,8 @@ enum DumpTableType DTT_CHAR_TABLE, // // character_achievement, character_achievement_progress, // character_action, character_aura, character_homebind, // character_queststatus, character_queststatus_rewarded, character_reputation, - // character_spell, character_spell_cooldown, character_ticket, character_talent + // character_spell, character_spell_cooldown, character_ticket, character_talent. + // character_cuf_profiles, character_currency DTT_EQSET_TABLE, // <- guid // character_equipmentsets diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index da6a7dc1929..1a6127daa89 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -16,7 +16,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "Cryptography/HMACSHA1.h" +#include "Cryptography/HmacHash.h" #include "Cryptography/WardenKeyGeneration.h" #include "Common.h" #include "WorldPacket.h" @@ -283,7 +283,7 @@ void WardenWin::RequestData() { uint32 seed = rand32(); buff << uint32(seed); - HmacHash hmac(4, (uint8*)&seed); + HmacSha1 hmac(4, (uint8*)&seed); hmac.UpdateData(wd->Str); hmac.Finalize(); buff.append(hmac.GetDigest(), hmac.GetLength()); diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp index dea7dfa6819..cab232931b9 100644 --- a/src/server/game/Weather/Weather.cpp +++ b/src/server/game/Weather/Weather.cpp @@ -28,6 +28,7 @@ #include "ObjectMgr.h" #include "Util.h" #include "ScriptMgr.h" +#include "Opcodes.h" #include "WorldSession.h" /// Create the Weather object diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h index 0bdd6af6dc5..ae83fa67a84 100644 --- a/src/server/game/Weather/Weather.h +++ b/src/server/game/Weather/Weather.h @@ -46,7 +46,7 @@ struct WeatherData enum WeatherState { WEATHER_STATE_FINE = 0, - WEATHER_STATE_FOG = 1, + WEATHER_STATE_FOG = 1, // Used in some instance encounters. WEATHER_STATE_LIGHT_RAIN = 3, WEATHER_STATE_MEDIUM_RAIN = 4, WEATHER_STATE_HEAVY_RAIN = 5, diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp index 938c91b0228..f18809b107a 100644 --- a/src/server/game/Weather/WeatherMgr.cpp +++ b/src/server/game/Weather/WeatherMgr.cpp @@ -26,6 +26,7 @@ #include "ObjectMgr.h" #include "Player.h" #include "WorldPacket.h" +#include "Opcodes.h" #include "WorldSession.h" namespace WeatherMgr diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 533fbe6b2a4..14591db9eb6 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -41,11 +41,13 @@ #include "ObjectMgr.h" #include "ArenaTeamMgr.h" #include "GuildMgr.h" +#include "GuildFinderMgr.h" #include "TicketMgr.h" #include "SpellMgr.h" #include "GroupMgr.h" #include "Chat.h" #include "DBCStores.h" +#include "DB2Stores.h" #include "LootMgr.h" #include "ItemEnchantmentMgr.h" #include "MapManager.h" @@ -114,6 +116,7 @@ World::World() m_NextMonthlyQuestReset = 0; m_NextRandomBGReset = 0; m_NextGuildReset = 0; + m_NextCurrencyReset = 0; m_defaultDbcLocale = LOCALE_enUS; m_availableDbcLocaleMask = 0; @@ -286,7 +289,7 @@ void World::AddSession_(WorldSession* s) return; } - s->SendAuthResponse(AUTH_OK, true); + s->SendAuthResponse(AUTH_OK, false); s->SendAddonsInfo(); s->SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION)); s->SendTutorialsData(); @@ -342,7 +345,7 @@ void World::AddQueuedPlayer(WorldSession* sess) m_QueuedPlayer.push_back(sess); // The 1st SMSG_AUTH_RESPONSE needs to contain other info too. - sess->SendAuthResponse(AUTH_WAIT_QUEUE, false, GetQueuePos(sess)); + sess->SendAuthResponse(AUTH_WAIT_QUEUE, true, GetQueuePos(sess)); } bool World::RemoveQueuedPlayer(WorldSession* sess) @@ -416,6 +419,16 @@ void World::LoadConfigSettings(bool reload) sLog->LoadFromConfig(); } + m_defaultDbcLocale = LocaleConstant(sConfigMgr->GetIntDefault("DBC.Locale", 0)); + + if (m_defaultDbcLocale >= TOTAL_LOCALES) + { + TC_LOG_ERROR("server.loading", "Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)", TOTAL_LOCALES); + m_defaultDbcLocale = LOCALE_enUS; + } + + TC_LOG_INFO("server.loading", "Using %s DBC Locale", localeNames[m_defaultDbcLocale]); + ///- Read the player limit and the Message of the day from the config file SetPlayerAmountLimit(sConfigMgr->GetIntDefault("PlayerLimit", 100)); SetMotd(sConfigMgr->GetStringDefault("Motd", "Welcome to a Trinity Core Server.")); @@ -777,57 +790,84 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_START_PLAYER_MONEY] = sConfigMgr->GetIntDefault("StartPlayerMoney", 0); if (int32(m_int_configs[CONFIG_START_PLAYER_MONEY]) < 0) { - TC_LOG_ERROR("server.loading", "StartPlayerMoney (%i) must be in range 0..%u. Set to %u.", m_int_configs[CONFIG_START_PLAYER_MONEY], MAX_MONEY_AMOUNT, 0); + TC_LOG_ERROR("server.loading", "StartPlayerMoney (%i) must be in range 0.." UI64FMTD ". Set to %u.", m_int_configs[CONFIG_START_PLAYER_MONEY], uint64(MAX_MONEY_AMOUNT), 0); m_int_configs[CONFIG_START_PLAYER_MONEY] = 0; } - else if (m_int_configs[CONFIG_START_PLAYER_MONEY] > MAX_MONEY_AMOUNT) + else if (m_int_configs[CONFIG_START_PLAYER_MONEY] > 0x7FFFFFFF-1) // TODO: (See MAX_MONEY_AMOUNT) { TC_LOG_ERROR("server.loading", "StartPlayerMoney (%i) must be in range 0..%u. Set to %u.", - m_int_configs[CONFIG_START_PLAYER_MONEY], MAX_MONEY_AMOUNT, MAX_MONEY_AMOUNT); - m_int_configs[CONFIG_START_PLAYER_MONEY] = MAX_MONEY_AMOUNT; + m_int_configs[CONFIG_START_PLAYER_MONEY], 0x7FFFFFFF-1, 0x7FFFFFFF-1); + m_int_configs[CONFIG_START_PLAYER_MONEY] = 0x7FFFFFFF-1; } - m_int_configs[CONFIG_MAX_HONOR_POINTS] = sConfigMgr->GetIntDefault("MaxHonorPoints", 75000); - if (int32(m_int_configs[CONFIG_MAX_HONOR_POINTS]) < 0) + m_int_configs[CONFIG_CURRENCY_RESET_HOUR] = sConfigMgr->GetIntDefault("Currency.ResetHour", 3); + if (m_int_configs[CONFIG_CURRENCY_RESET_HOUR] > 23) { - TC_LOG_ERROR("server.loading", "MaxHonorPoints (%i) can't be negative. Set to 0.", m_int_configs[CONFIG_MAX_HONOR_POINTS]); - m_int_configs[CONFIG_MAX_HONOR_POINTS] = 0; + TC_LOG_ERROR("server.loading", "Currency.ResetHour (%i) can't be load. Set to 6.", m_int_configs[CONFIG_CURRENCY_RESET_HOUR]); + m_int_configs[CONFIG_CURRENCY_RESET_HOUR] = 3; + } + m_int_configs[CONFIG_CURRENCY_RESET_DAY] = sConfigMgr->GetIntDefault("Currency.ResetDay", 3); + if (m_int_configs[CONFIG_CURRENCY_RESET_DAY] > 6) + { + TC_LOG_ERROR("server.loading", "Currency.ResetDay (%i) can't be load. Set to 3.", m_int_configs[CONFIG_CURRENCY_RESET_DAY]); + m_int_configs[CONFIG_CURRENCY_RESET_DAY] = 3; + } + m_int_configs[CONFIG_CURRENCY_RESET_INTERVAL] = sConfigMgr->GetIntDefault("Currency.ResetInterval", 7); + if (int32(m_int_configs[CONFIG_CURRENCY_RESET_INTERVAL]) <= 0) + { + TC_LOG_ERROR("server.loading", "Currency.ResetInterval (%i) must be > 0, set to default 7.", m_int_configs[CONFIG_CURRENCY_RESET_INTERVAL]); + m_int_configs[CONFIG_CURRENCY_RESET_INTERVAL] = 7; } - m_int_configs[CONFIG_START_HONOR_POINTS] = sConfigMgr->GetIntDefault("StartHonorPoints", 0); - if (int32(m_int_configs[CONFIG_START_HONOR_POINTS]) < 0) + m_int_configs[CONFIG_CURRENCY_START_HONOR_POINTS] = sConfigMgr->GetIntDefault("Currency.StartHonorPoints", 0); + if (int32(m_int_configs[CONFIG_CURRENCY_START_HONOR_POINTS]) < 0) { - TC_LOG_ERROR("server.loading", "StartHonorPoints (%i) must be in range 0..MaxHonorPoints(%u). Set to %u.", - m_int_configs[CONFIG_START_HONOR_POINTS], m_int_configs[CONFIG_MAX_HONOR_POINTS], 0); - m_int_configs[CONFIG_START_HONOR_POINTS] = 0; + TC_LOG_ERROR("server.loading", "Currency.StartHonorPoints (%i) must be >= 0, set to default 0.", m_int_configs[CONFIG_CURRENCY_START_HONOR_POINTS]); + m_int_configs[CONFIG_CURRENCY_START_HONOR_POINTS] = 0; } - else if (m_int_configs[CONFIG_START_HONOR_POINTS] > m_int_configs[CONFIG_MAX_HONOR_POINTS]) + m_int_configs[CONFIG_CURRENCY_MAX_HONOR_POINTS] = sConfigMgr->GetIntDefault("Currency.MaxHonorPoints", 4000); + if (int32(m_int_configs[CONFIG_CURRENCY_MAX_HONOR_POINTS]) < 0) { - TC_LOG_ERROR("server.loading", "StartHonorPoints (%i) must be in range 0..MaxHonorPoints(%u). Set to %u.", - m_int_configs[CONFIG_START_HONOR_POINTS], m_int_configs[CONFIG_MAX_HONOR_POINTS], m_int_configs[CONFIG_MAX_HONOR_POINTS]); - m_int_configs[CONFIG_START_HONOR_POINTS] = m_int_configs[CONFIG_MAX_HONOR_POINTS]; + TC_LOG_ERROR("server.loading", "Currency.MaxHonorPoints (%i) can't be negative. Set to default 4000.", m_int_configs[CONFIG_CURRENCY_MAX_HONOR_POINTS]); + m_int_configs[CONFIG_CURRENCY_MAX_HONOR_POINTS] = 4000; } + m_int_configs[CONFIG_CURRENCY_MAX_HONOR_POINTS] *= 100; //precision mod - m_int_configs[CONFIG_MAX_ARENA_POINTS] = sConfigMgr->GetIntDefault("MaxArenaPoints", 10000); - if (int32(m_int_configs[CONFIG_MAX_ARENA_POINTS]) < 0) + m_int_configs[CONFIG_CURRENCY_START_JUSTICE_POINTS] = sConfigMgr->GetIntDefault("Currency.StartJusticePoints", 0); + if (int32(m_int_configs[CONFIG_CURRENCY_START_JUSTICE_POINTS]) < 0) + { + TC_LOG_ERROR("server.loading", "Currency.StartJusticePoints (%i) must be >= 0, set to default 0.", m_int_configs[CONFIG_CURRENCY_START_JUSTICE_POINTS]); + m_int_configs[CONFIG_CURRENCY_START_JUSTICE_POINTS] = 0; + } + m_int_configs[CONFIG_CURRENCY_MAX_JUSTICE_POINTS] = sConfigMgr->GetIntDefault("Currency.MaxJusticePoints", 4000); + if (int32(m_int_configs[CONFIG_CURRENCY_MAX_JUSTICE_POINTS]) < 0) { - TC_LOG_ERROR("server.loading", "MaxArenaPoints (%i) can't be negative. Set to 0.", m_int_configs[CONFIG_MAX_ARENA_POINTS]); - m_int_configs[CONFIG_MAX_ARENA_POINTS] = 0; + TC_LOG_ERROR("server.loading", "Currency.MaxJusticePoints (%i) can't be negative. Set to default 4000.", m_int_configs[CONFIG_CURRENCY_MAX_JUSTICE_POINTS]); + m_int_configs[CONFIG_CURRENCY_MAX_JUSTICE_POINTS] = 4000; } + m_int_configs[CONFIG_CURRENCY_MAX_JUSTICE_POINTS] *= 100; //precision mod - m_int_configs[CONFIG_START_ARENA_POINTS] = sConfigMgr->GetIntDefault("StartArenaPoints", 0); - if (int32(m_int_configs[CONFIG_START_ARENA_POINTS]) < 0) + m_int_configs[CONFIG_CURRENCY_START_CONQUEST_POINTS] = sConfigMgr->GetIntDefault("Currency.StartConquestPoints", 0); + if (int32(m_int_configs[CONFIG_CURRENCY_START_CONQUEST_POINTS]) < 0) { - TC_LOG_ERROR("server.loading", "StartArenaPoints (%i) must be in range 0..MaxArenaPoints(%u). Set to %u.", - m_int_configs[CONFIG_START_ARENA_POINTS], m_int_configs[CONFIG_MAX_ARENA_POINTS], 0); - m_int_configs[CONFIG_START_ARENA_POINTS] = 0; + TC_LOG_ERROR("server.loading", "Currency.StartConquestPoints (%i) must be >= 0, set to default 0.", m_int_configs[CONFIG_CURRENCY_START_CONQUEST_POINTS]); + m_int_configs[CONFIG_CURRENCY_START_CONQUEST_POINTS] = 0; } - else if (m_int_configs[CONFIG_START_ARENA_POINTS] > m_int_configs[CONFIG_MAX_ARENA_POINTS]) + m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_WEEK_CAP] = sConfigMgr->GetIntDefault("Currency.ConquestPointsWeekCap", 1650); + if (int32(m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_WEEK_CAP]) <= 0) { - TC_LOG_ERROR("server.loading", "StartArenaPoints (%i) must be in range 0..MaxArenaPoints(%u). Set to %u.", - m_int_configs[CONFIG_START_ARENA_POINTS], m_int_configs[CONFIG_MAX_ARENA_POINTS], m_int_configs[CONFIG_MAX_ARENA_POINTS]); - m_int_configs[CONFIG_START_ARENA_POINTS] = m_int_configs[CONFIG_MAX_ARENA_POINTS]; + TC_LOG_ERROR("server.loading", "Currency.ConquestPointsWeekCap (%i) must be > 0, set to default 1650.", m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_WEEK_CAP]); + m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_WEEK_CAP] = 1650; } + m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_WEEK_CAP] *= 100; //precision mod + + m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD] = sConfigMgr->GetIntDefault("Currency.ConquestPointsArenaReward", 180); + if (int32(m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD]) <= 0) + { + TC_LOG_ERROR("server.loading", "Currency.ConquestPointsArenaReward (%i) must be > 0, set to default 180.", m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD]); + m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD] = 180; + } + m_int_configs[CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD] *= 100; //precision mod m_int_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL] = sConfigMgr->GetIntDefault("RecruitAFriend.MaxLevel", 60); if (m_int_configs[CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL] > m_int_configs[CONFIG_MAX_PLAYER_LEVEL]) @@ -924,13 +964,10 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_SKILL_GAIN_CRAFTING] = sConfigMgr->GetIntDefault("SkillGain.Crafting", 1); - m_int_configs[CONFIG_SKILL_GAIN_DEFENSE] = sConfigMgr->GetIntDefault("SkillGain.Defense", 1); - m_int_configs[CONFIG_SKILL_GAIN_GATHERING] = sConfigMgr->GetIntDefault("SkillGain.Gathering", 1); - m_int_configs[CONFIG_SKILL_GAIN_WEAPON] = sConfigMgr->GetIntDefault("SkillGain.Weapon", 1); - m_int_configs[CONFIG_MAX_OVERSPEED_PINGS] = sConfigMgr->GetIntDefault("MaxOverspeedPings", 2); + if (m_int_configs[CONFIG_MAX_OVERSPEED_PINGS] != 0 && m_int_configs[CONFIG_MAX_OVERSPEED_PINGS] < 2) { TC_LOG_ERROR("server.loading", "MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check). Set to 2.", m_int_configs[CONFIG_MAX_OVERSPEED_PINGS]); @@ -942,8 +979,6 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_DISABLE_BREATHING] = sConfigMgr->GetIntDefault("DisableWaterBreath", SEC_CONSOLE); - m_bool_configs[CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL] = sConfigMgr->GetBoolDefault("AlwaysMaxSkillForLevel", false); - if (reload) { uint32 val = sConfigMgr->GetIntDefault("Expansion", 2); @@ -1017,6 +1052,7 @@ void World::LoadConfigSettings(bool reload) // always use declined names in the russian client m_bool_configs[CONFIG_DECLINED_NAMES_USED] = + (m_int_configs[CONFIG_REALM_ZONE] == REALM_ZONE_RUSSIAN) ? true : sConfigMgr->GetBoolDefault("DeclinedNames", false); m_float_configs[CONFIG_LISTEN_RANGE_SAY] = sConfigMgr->GetFloatDefault("ListenRange.Say", 25.0f); @@ -1033,8 +1069,6 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfigMgr->GetIntDefault ("Arena.MaxRatingDifference", 150); m_int_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfigMgr->GetIntDefault ("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS); m_int_configs[CONFIG_ARENA_RATED_UPDATE_TIMER] = sConfigMgr->GetIntDefault ("Arena.RatedUpdateTimer", 5 * IN_MILLISECONDS); - m_bool_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfigMgr->GetBoolDefault("Arena.AutoDistributePoints", false); - m_int_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfigMgr->GetIntDefault ("Arena.AutoDistributeInterval", 7); m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetBoolDefault("Arena.QueueAnnouncer.Enable", false); m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetBoolDefault("Arena.QueueAnnouncer.PlayerOnly", false); m_int_configs[CONFIG_ARENA_SEASON_ID] = sConfigMgr->GetIntDefault ("Arena.ArenaSeason.ID", 1); @@ -1060,6 +1094,9 @@ void World::LoadConfigSettings(bool reload) TC_LOG_ERROR("server.loading", "ClientCacheVersion can't be negative %d, ignored.", clientCacheId); } + m_int_configs[CONFIG_GUILD_NEWS_LOG_COUNT] = sConfigMgr->GetIntDefault("Guild.NewsLogRecordsCount", GUILD_NEWSLOG_MAX_RECORDS); + if (m_int_configs[CONFIG_GUILD_NEWS_LOG_COUNT] > GUILD_NEWSLOG_MAX_RECORDS) + m_int_configs[CONFIG_GUILD_NEWS_LOG_COUNT] = GUILD_NEWSLOG_MAX_RECORDS; m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] = sConfigMgr->GetIntDefault("Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS); if (m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] > GUILD_EVENTLOG_MAX_RECORDS) m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] = GUILD_EVENTLOG_MAX_RECORDS; @@ -1200,12 +1237,12 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_ACC_PASSCHANGESEC] = sConfigMgr->GetIntDefault("Account.PasswordChangeSecurity", 0); // Random Battleground Rewards - m_int_configs[CONFIG_BG_REWARD_WINNER_HONOR_FIRST] = sConfigMgr->GetIntDefault("Battleground.RewardWinnerHonorFirst", 30); - m_int_configs[CONFIG_BG_REWARD_WINNER_ARENA_FIRST] = sConfigMgr->GetIntDefault("Battleground.RewardWinnerArenaFirst", 25); - m_int_configs[CONFIG_BG_REWARD_WINNER_HONOR_LAST] = sConfigMgr->GetIntDefault("Battleground.RewardWinnerHonorLast", 15); - m_int_configs[CONFIG_BG_REWARD_WINNER_ARENA_LAST] = sConfigMgr->GetIntDefault("Battleground.RewardWinnerArenaLast", 0); - m_int_configs[CONFIG_BG_REWARD_LOSER_HONOR_FIRST] = sConfigMgr->GetIntDefault("Battleground.RewardLoserHonorFirst", 5); - m_int_configs[CONFIG_BG_REWARD_LOSER_HONOR_LAST] = sConfigMgr->GetIntDefault("Battleground.RewardLoserHonorLast", 5); + m_int_configs[CONFIG_BG_REWARD_WINNER_HONOR_FIRST] = sConfigMgr->GetIntDefault("Battleground.RewardWinnerHonorFirst", 27000); + m_int_configs[CONFIG_BG_REWARD_WINNER_CONQUEST_FIRST] = sConfigMgr->GetIntDefault("Battleground.RewardWinnerConquestFirst", 10000); + m_int_configs[CONFIG_BG_REWARD_WINNER_HONOR_LAST] = sConfigMgr->GetIntDefault("Battleground.RewardWinnerHonorLast", 13500); + m_int_configs[CONFIG_BG_REWARD_WINNER_CONQUEST_LAST] = sConfigMgr->GetIntDefault("Battleground.RewardWinnerConquestLast", 5000); + m_int_configs[CONFIG_BG_REWARD_LOSER_HONOR_FIRST] = sConfigMgr->GetIntDefault("Battleground.RewardLoserHonorFirst", 4500); + m_int_configs[CONFIG_BG_REWARD_LOSER_HONOR_LAST] = sConfigMgr->GetIntDefault("Battleground.RewardLoserHonorLast", 3500); // Max instances per hour m_int_configs[CONFIG_MAX_INSTANCES_PER_HOUR] = sConfigMgr->GetIntDefault("AccountInstancesPerHour", 5); @@ -1226,6 +1263,15 @@ void World::LoadConfigSettings(bool reload) // MySQL ping time interval m_int_configs[CONFIG_DB_PING_INTERVAL] = sConfigMgr->GetIntDefault("MaxPingTime", 30); + // Guild save interval + m_bool_configs[CONFIG_GUILD_LEVELING_ENABLED] = sConfigMgr->GetBoolDefault("Guild.LevelingEnabled", true); + m_int_configs[CONFIG_GUILD_SAVE_INTERVAL] = sConfigMgr->GetIntDefault("Guild.SaveInterval", 15); + m_int_configs[CONFIG_GUILD_MAX_LEVEL] = sConfigMgr->GetIntDefault("Guild.MaxLevel", 25); + m_int_configs[CONFIG_GUILD_UNDELETABLE_LEVEL] = sConfigMgr->GetIntDefault("Guild.UndeletableLevel", 4); + rate_values[RATE_XP_GUILD_MODIFIER] = sConfigMgr->GetFloatDefault("Guild.XPModifier", 0.25f); + m_int_configs[CONFIG_GUILD_DAILY_XP_CAP] = sConfigMgr->GetIntDefault("Guild.DailyXPCap", 7807500); + m_int_configs[CONFIG_GUILD_WEEKLY_REP_CAP] = sConfigMgr->GetIntDefault("Guild.WeeklyReputationCap", 4375); + // misc m_bool_configs[CONFIG_PDUMP_NO_PATHS] = sConfigMgr->GetBoolDefault("PlayerDump.DisallowPaths", true); m_bool_configs[CONFIG_PDUMP_NO_OVERWRITE] = sConfigMgr->GetBoolDefault("PlayerDump.DisallowOverwrite", true); @@ -1255,8 +1301,6 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_PACKET_SPOOF_BANDURATION] = sConfigMgr->GetIntDefault("PacketSpoof.BanDuration", 86400); - m_int_configs[CONFIG_BIRTHDAY_TIME] = sConfigMgr->GetIntDefault("BirthdayTime", 1222964635); - m_bool_configs[CONFIG_IP_BASED_ACTION_LOGGING] = sConfigMgr->GetBoolDefault("Allow.IP.Based.Action.Logging", false); // call ScriptMgr if we're reloading the configuration @@ -1331,7 +1375,7 @@ void World::SetInitialWorldSettings() ///- Load the DBC files TC_LOG_INFO("server.loading", "Initialize data stores..."); LoadDBCStores(m_dataPath); - DetectDBCLang(); + LoadDB2Stores(m_dataPath); TC_LOG_INFO("server.loading", "Loading SpellInfo store..."); sSpellMgr->LoadSpellInfoStore(); @@ -1367,7 +1411,6 @@ void World::SetInitialWorldSettings() sObjectMgr->LoadCreatureLocales(); sObjectMgr->LoadGameObjectLocales(); sObjectMgr->LoadItemLocales(); - sObjectMgr->LoadItemSetNameLocales(); sObjectMgr->LoadQuestLocales(); sObjectMgr->LoadNpcTextLocales(); sObjectMgr->LoadPageTextLocales(); @@ -1419,6 +1462,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Spell Group Stack Rules..."); sSpellMgr->LoadSpellGroupStackRules(); + TC_LOG_INFO("server.loading", "Loading Spell Phase Dbc Info..."); + sObjectMgr->LoadPhaseInfo(); + TC_LOG_INFO("server.loading", "Loading NPC Texts..."); sObjectMgr->LoadGossipText(); @@ -1435,7 +1481,10 @@ void World::SetInitialWorldSettings() sObjectMgr->LoadItemTemplates(); TC_LOG_INFO("server.loading", "Loading Item set names..."); // must be after LoadItemPrototypes - sObjectMgr->LoadItemSetNames(); + sObjectMgr->LoadItemTemplateAddon(); + + TC_LOG_INFO("misc", "Loading Item Scripts..."); // must be after LoadItemPrototypes + sObjectMgr->LoadItemScriptNames(); TC_LOG_INFO("server.loading", "Loading Creature Model Based Info Data..."); sObjectMgr->LoadCreatureModelInfo(); @@ -1545,6 +1594,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Graveyard-zone links..."); sObjectMgr->LoadGraveyardZones(); + TC_LOG_INFO("server.loading", "Loading Graveyard Orientations..."); + sObjectMgr->LoadGraveyardOrientations(); + TC_LOG_INFO("server.loading", "Loading spell pet auras..."); sSpellMgr->LoadSpellPetAuras(); @@ -1616,9 +1668,17 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Auctions..."); sAuctionMgr->LoadAuctions(); + TC_LOG_INFO("server.loading", "Loading Guild XP for level..."); + sGuildMgr->LoadGuildXpForLevel(); + + TC_LOG_INFO("server.loading", "Loading Guild rewards..."); + sGuildMgr->LoadGuildRewards(); + TC_LOG_INFO("server.loading", "Loading Guilds..."); sGuildMgr->LoadGuilds(); + sGuildFinderMgr->LoadFromDB(); + TC_LOG_INFO("server.loading", "Loading ArenaTeams..."); sArenaTeamMgr->LoadArenaTeams(); @@ -1661,6 +1721,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading World States..."); // must be loaded before battleground, outdoor PvP and conditions LoadWorldStates(); + TC_LOG_INFO("server.loading", "Loading Phase definitions..."); + sObjectMgr->LoadPhaseDefinitions(); + TC_LOG_INFO("server.loading", "Loading Conditions..."); sConditionMgr->LoadConditions(); @@ -1746,6 +1809,8 @@ void World::SetInitialWorldSettings() m_timers[WUPDATE_PINGDB].SetInterval(getIntConfig(CONFIG_DB_PING_INTERVAL)*MINUTE*IN_MILLISECONDS); // Mysql ping time in minutes + m_timers[WUPDATE_GUILDSAVE].SetInterval(getIntConfig(CONFIG_GUILD_SAVE_INTERVAL) * MINUTE * IN_MILLISECONDS); + //to set mailtimer to return mails every day between 4 and 5 am //mailtimer is increased when updating auctions //one second is 1000 -(tested on win system) @@ -1782,7 +1847,6 @@ void World::SetInitialWorldSettings() ///- Initialize Battlegrounds TC_LOG_INFO("server.loading", "Starting Battleground System"); sBattlegroundMgr->LoadBattlegroundTemplates(); - sBattlegroundMgr->InitAutomaticArenaPointDistribution(); ///- Initialize outdoor pvp TC_LOG_INFO("server.loading", "Starting Outdoor PvP System"); @@ -1820,8 +1884,20 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Calculate guild limitation(s) reset time..."); InitGuildResetTime(); + TC_LOG_INFO("server.loading", "Calculate next currency reset time..."); + InitCurrencyResetTime(); + LoadCharacterNameData(); + TC_LOG_INFO("misc", "Initializing Opcodes..."); + opcodeTable.Initialize(); + + TC_LOG_INFO("misc", "Loading hotfix info..."); + sObjectMgr->LoadHotfixData(); + + TC_LOG_INFO("server.loading", "Loading missing KeyChains..."); + sObjectMgr->LoadMissingKeyChains(); + uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); TC_LOG_INFO("server.worldserver", "World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000)); @@ -1830,49 +1906,6 @@ void World::SetInitialWorldSettings() sLog->SetRealmId(realmId); } -void World::DetectDBCLang() -{ - uint8 m_lang_confid = sConfigMgr->GetIntDefault("DBC.Locale", 255); - - if (m_lang_confid != 255 && m_lang_confid >= TOTAL_LOCALES) - { - TC_LOG_ERROR("server.loading", "Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)", TOTAL_LOCALES); - m_lang_confid = LOCALE_enUS; - } - - ChrRacesEntry const* race = sChrRacesStore.LookupEntry(1); - - std::string availableLocalsStr; - - uint8 default_locale = TOTAL_LOCALES; - for (uint8 i = default_locale-1; i < TOTAL_LOCALES; --i) // -1 will be 255 due to uint8 - { - if (race->name[i][0] != '\0') // check by race names - { - default_locale = i; - m_availableDbcLocaleMask |= (1 << i); - availableLocalsStr += localeNames[i]; - availableLocalsStr += " "; - } - } - - if (default_locale != m_lang_confid && m_lang_confid < TOTAL_LOCALES && - (m_availableDbcLocaleMask & (1 << m_lang_confid))) - { - default_locale = m_lang_confid; - } - - if (default_locale >= TOTAL_LOCALES) - { - TC_LOG_ERROR("server.loading", "Unable to determine your DBC Locale! (corrupt DBC?)"); - exit(1); - } - - m_defaultDbcLocale = LocaleConstant(default_locale); - - TC_LOG_INFO("server.loading", "Using %s DBC Locale as default. All available DBC locales: %s", localeNames[m_defaultDbcLocale], availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str()); -} - void World::RecordTimeDiff(const char *text, ...) { if (m_updateTimeCount != 1) @@ -1986,6 +2019,9 @@ void World::Update(uint32 diff) if (m_gameTime > m_NextGuildReset) ResetGuildCap(); + if (m_gameTime > m_NextCurrencyReset) + ResetCurrencyWeekCap(); + /// <ul><li> Handle auctions when the timer has passed if (m_timers[WUPDATE_AUCTIONS].Passed()) { @@ -2113,6 +2149,12 @@ void World::Update(uint32 diff) WorldDatabase.KeepAlive(); } + if (m_timers[WUPDATE_GUILDSAVE].Passed()) + { + m_timers[WUPDATE_GUILDSAVE].Reset(); + sGuildMgr->SaveGuilds(); + } + // update the instance reset times sInstanceSaveMgr->Update(); @@ -2712,16 +2754,20 @@ void World::SendAutoBroadcast() sWorld->SendWorldText(LANG_AUTO_BROADCAST, msg.c_str()); else if (abcenter == 1) { - WorldPacket data(SMSG_NOTIFICATION, (msg.size()+1)); - data << msg; + WorldPacket data(SMSG_NOTIFICATION, 2 + msg.length()); + data.WriteBits(msg.length(), 13); + data.FlushBits(); + data.WriteString(msg); sWorld->SendGlobalMessage(&data); } else if (abcenter == 2) { sWorld->SendWorldText(LANG_AUTO_BROADCAST, msg.c_str()); - WorldPacket data(SMSG_NOTIFICATION, (msg.size()+1)); - data << msg; + WorldPacket data(SMSG_NOTIFICATION, 2 + msg.length()); + data.WriteBits(msg.length(), 13); + data.FlushBits(); + data.WriteString(msg); sWorld->SendGlobalMessage(&data); } @@ -2861,6 +2907,35 @@ void World::InitGuildResetTime() sWorld->setWorldState(WS_GUILD_DAILY_RESET_TIME, uint64(m_NextGuildReset)); } +void World::InitCurrencyResetTime() +{ + time_t currencytime = uint64(sWorld->getWorldState(WS_CURRENCY_RESET_TIME)); + if (!currencytime) + m_NextCurrencyReset = time_t(time(NULL)); // game time not yet init + + // generate time by config + time_t curTime = time(NULL); + tm localTm = *localtime(&curTime); + + localTm.tm_wday = getIntConfig(CONFIG_CURRENCY_RESET_DAY); + localTm.tm_hour = getIntConfig(CONFIG_CURRENCY_RESET_HOUR); + localTm.tm_min = 0; + localTm.tm_sec = 0; + + // current week reset time + time_t nextWeekResetTime = mktime(&localTm); + + // next reset time before current moment + if (curTime >= nextWeekResetTime) + nextWeekResetTime += getIntConfig(CONFIG_CURRENCY_RESET_INTERVAL) * DAY; + + // normalize reset time + m_NextCurrencyReset = currencytime < curTime ? nextWeekResetTime - getIntConfig(CONFIG_CURRENCY_RESET_INTERVAL) * DAY : nextWeekResetTime; + + if (!currencytime) + sWorld->setWorldState(WS_CURRENCY_RESET_TIME, uint64(m_NextCurrencyReset)); +} + void World::ResetDailyQuests() { TC_LOG_INFO("misc", "Daily quests reset for all characters."); @@ -2876,6 +2951,18 @@ void World::ResetDailyQuests() sPoolMgr->ChangeDailyQuests(); } +void World::ResetCurrencyWeekCap() +{ + CharacterDatabase.Execute("UPDATE `character_currency` SET `week_count` = 0"); + + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + if (itr->second->GetPlayer()) + itr->second->GetPlayer()->ResetCurrencyWeekCap(); + + m_NextCurrencyReset = time_t(m_NextCurrencyReset + DAY * getIntConfig(CONFIG_CURRENCY_RESET_INTERVAL)); + sWorld->setWorldState(WS_CURRENCY_RESET_TIME, uint64(m_NextCurrencyReset)); +} + void World::LoadDBAllowedSecurityLevel() { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL); @@ -2987,11 +3074,14 @@ void World::ResetRandomBG() void World::ResetGuildCap() { - TC_LOG_INFO("misc", "Guild Daily Cap reset."); - m_NextGuildReset = time_t(m_NextGuildReset + DAY); sWorld->setWorldState(WS_GUILD_DAILY_RESET_TIME, uint64(m_NextGuildReset)); - sGuildMgr->ResetTimes(); + uint32 week = getWorldState(WS_GUILD_WEEKLY_RESET_TIME); + week = week < 7 ? week + 1 : 1; + + TC_LOG_INFO("misc", "Guild Daily Cap reset. Week: %u", week == 1); + sWorld->setWorldState(WS_GUILD_WEEKLY_RESET_TIME, week); + sGuildMgr->ResetTimes(week == 1); } void World::UpdateMaxSessionCounters() @@ -3195,6 +3285,11 @@ CharacterNameData const* World::GetCharacterNameData(uint32 guid) const return NULL; } +void World::UpdatePhaseDefinitions() +{ + +} + void World::ReloadRBAC() { // Passive reload, we mark the data as invalidated and next time a permission is checked it will be reloaded diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 7d3c7694463..00c897a6f00 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -44,11 +44,19 @@ class SystemMgr; // ServerMessages.dbc enum ServerMessageType { - SERVER_MSG_SHUTDOWN_TIME = 1, - SERVER_MSG_RESTART_TIME = 2, - SERVER_MSG_STRING = 3, - SERVER_MSG_SHUTDOWN_CANCELLED = 4, - SERVER_MSG_RESTART_CANCELLED = 5 + SERVER_MSG_SHUTDOWN_TIME = 1, + SERVER_MSG_RESTART_TIME = 2, + SERVER_MSG_STRING = 3, + SERVER_MSG_SHUTDOWN_CANCELLED = 4, + SERVER_MSG_RESTART_CANCELLED = 5, + SERVER_MSG_BG_SHUTDOWN_TIME = 6, + SERVER_MSG_BG_RESTART_TIME = 7, + SERVER_MSG_INSTANCE_SHUTDOWN_TIME = 8, + SERVER_MSG_INSTANCE_RESTART_TIME = 9, + SERVER_MSG_CONTENT_READY = 10, + SERVER_MSG_TICKET_SERVICED_SOON = 11, + SERVER_MSG_WAIT_TIME_UNAVAILABLE = 12, + SERVER_MSG_TICKET_WAIT_TIME = 13, }; enum ShutdownMask @@ -77,6 +85,7 @@ enum WorldTimers WUPDATE_MAILBOXQUEUE, WUPDATE_DELETECHARS, WUPDATE_PINGDB, + WUPDATE_GUILDSAVE, WUPDATE_COUNT }; @@ -106,7 +115,6 @@ enum WorldBoolConfigs CONFIG_SKILL_MILLING, CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY, CONFIG_WEATHER, - CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL, CONFIG_QUEST_IGNORE_RAID, CONFIG_DETECT_POS_COLLISION, CONFIG_RESTRICTED_LFG_CHANNEL, @@ -122,7 +130,6 @@ enum WorldBoolConfigs CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE, CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY, CONFIG_BG_XP_FOR_KILL, - CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS, CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE, CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY, CONFIG_ARENA_SEASON_IN_PROGRESS, @@ -149,6 +156,7 @@ enum WorldBoolConfigs CONFIG_WARDEN_ENABLED, CONFIG_ENABLE_MMAPS, CONFIG_WINTERGRASP_ENABLE, + CONFIG_GUILD_LEVELING_ENABLED, CONFIG_UI_QUESTLEVELS_IN_DIALOGS, // Should we add quest levels to the title in the NPC dialogs? CONFIG_EVENT_ANNOUNCE, CONFIG_STATS_LIMITS_ENABLE, @@ -209,10 +217,16 @@ enum WorldIntConfigs CONFIG_START_PLAYER_LEVEL, CONFIG_START_HEROIC_PLAYER_LEVEL, CONFIG_START_PLAYER_MONEY, - CONFIG_MAX_HONOR_POINTS, - CONFIG_START_HONOR_POINTS, - CONFIG_MAX_ARENA_POINTS, - CONFIG_START_ARENA_POINTS, + CONFIG_CURRENCY_START_JUSTICE_POINTS, + CONFIG_CURRENCY_MAX_JUSTICE_POINTS, + CONFIG_CURRENCY_START_HONOR_POINTS, + CONFIG_CURRENCY_MAX_HONOR_POINTS, + CONFIG_CURRENCY_START_CONQUEST_POINTS, + CONFIG_CURRENCY_CONQUEST_POINTS_WEEK_CAP, + CONFIG_CURRENCY_CONQUEST_POINTS_ARENA_REWARD, + CONFIG_CURRENCY_RESET_HOUR, + CONFIG_CURRENCY_RESET_DAY, + CONFIG_CURRENCY_RESET_INTERVAL, CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL, CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE, CONFIG_INSTANCE_RESET_TIME_HOUR, @@ -237,9 +251,7 @@ enum WorldIntConfigs CONFIG_SKILL_CHANCE_MINING_STEPS, CONFIG_SKILL_CHANCE_SKINNING_STEPS, CONFIG_SKILL_GAIN_CRAFTING, - CONFIG_SKILL_GAIN_DEFENSE, CONFIG_SKILL_GAIN_GATHERING, - CONFIG_SKILL_GAIN_WEAPON, CONFIG_MAX_OVERSPEED_PINGS, CONFIG_EXPANSION, CONFIG_CHATFLOOD_MESSAGE_COUNT, @@ -273,7 +285,6 @@ enum WorldIntConfigs CONFIG_ARENA_MAX_RATING_DIFFERENCE, CONFIG_ARENA_RATING_DISCARD_TIMER, CONFIG_ARENA_RATED_UPDATE_TIMER, - CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS, CONFIG_ARENA_SEASON_ID, CONFIG_ARENA_START_RATING, CONFIG_ARENA_START_PERSONAL_RATING, @@ -291,6 +302,7 @@ enum WorldIntConfigs CONFIG_LOGDB_CLEARINTERVAL, CONFIG_LOGDB_CLEARTIME, CONFIG_CLIENTCACHE_VERSION, + CONFIG_GUILD_NEWS_LOG_COUNT, CONFIG_GUILD_EVENT_LOG_COUNT, CONFIG_GUILD_BANK_EVENT_LOG_COUNT, CONFIG_MIN_LEVEL_STAT_SAVE, @@ -320,17 +332,21 @@ enum WorldIntConfigs CONFIG_WINTERGRASP_BATTLETIME, CONFIG_WINTERGRASP_NOBATTLETIME, CONFIG_WINTERGRASP_RESTART_AFTER_CRASH, + CONFIG_GUILD_SAVE_INTERVAL, + CONFIG_GUILD_MAX_LEVEL, + CONFIG_GUILD_UNDELETABLE_LEVEL, + CONFIG_GUILD_DAILY_XP_CAP, + CONFIG_GUILD_WEEKLY_REP_CAP, CONFIG_PACKET_SPOOF_POLICY, CONFIG_PACKET_SPOOF_BANMODE, CONFIG_PACKET_SPOOF_BANDURATION, CONFIG_ACC_PASSCHANGESEC, CONFIG_BG_REWARD_WINNER_HONOR_FIRST, - CONFIG_BG_REWARD_WINNER_ARENA_FIRST, CONFIG_BG_REWARD_WINNER_HONOR_LAST, - CONFIG_BG_REWARD_WINNER_ARENA_LAST, CONFIG_BG_REWARD_LOSER_HONOR_FIRST, CONFIG_BG_REWARD_LOSER_HONOR_LAST, - CONFIG_BIRTHDAY_TIME, + CONFIG_BG_REWARD_WINNER_CONQUEST_FIRST, + CONFIG_BG_REWARD_WINNER_CONQUEST_LAST, CONFIG_CREATURE_PICKPOCKET_REFILL, INT_CONFIG_VALUE_COUNT }; @@ -359,6 +375,7 @@ enum Rates RATE_DROP_MONEY, RATE_XP_KILL, RATE_XP_QUEST, + RATE_XP_GUILD_MODIFIER, RATE_XP_EXPLORE, RATE_REPAIRCOST, RATE_REPUTATION_GAIN, @@ -477,6 +494,8 @@ enum WorldStates WS_CLEANING_FLAGS = 20004, // Cleaning Flags WS_GUILD_DAILY_RESET_TIME = 20006, // Next guild cap reset time WS_MONTHLY_QUEST_RESET_TIME = 20007, // Next monthly reset time + // Cata specific custom worldstates + WS_GUILD_WEEKLY_RESET_TIME = 20050, // Next guild week reset time }; /// Storage class for commands issued for delayed execution @@ -613,7 +632,7 @@ class World /// Get the maximum skill level a player can reach uint16 GetConfigMaxSkillValue() const { - uint16 lvl = uint16(getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); + uint8 lvl = uint8(getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); return lvl > 60 ? 300 + ((lvl - 60) * 75) / 10 : lvl * 5; } @@ -741,6 +760,7 @@ class World void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; } void ResetEventSeasonalQuests(uint16 event_id); + void UpdatePhaseDefinitions(); void ReloadRBAC(); protected: @@ -753,11 +773,13 @@ class World void InitMonthlyQuestResetTime(); void InitRandomBGResetTime(); void InitGuildResetTime(); + void InitCurrencyResetTime(); void ResetDailyQuests(); void ResetWeeklyQuests(); void ResetMonthlyQuests(); void ResetRandomBG(); void ResetGuildCap(); + void ResetCurrencyWeekCap(); private: World(); ~World(); @@ -800,7 +822,6 @@ class World AccountTypes m_allowedSecurityLevel; LocaleConstant m_defaultDbcLocale; // from config for one from loaded DBC locales uint32 m_availableDbcLocaleMask; // by loaded DBC - void DetectDBCLang(); bool m_allowMovement; std::string m_motd; std::string m_dataPath; @@ -817,12 +838,13 @@ class World // CLI command holder to be thread safe LockedQueue<CliCommandHolder*> cliCmdQueue; - // next daily quests and random bg reset time + // scheduled reset times time_t m_NextDailyQuestReset; time_t m_NextWeeklyQuestReset; time_t m_NextMonthlyQuestReset; time_t m_NextRandomBGReset; time_t m_NextGuildReset; + time_t m_NextCurrencyReset; //Player Queue Queue m_QueuedPlayer; |