diff options
Diffstat (limited to 'src')
135 files changed, 5214 insertions, 2110 deletions
diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index 20d1193b8e2..e1c0b187c46 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -57,9 +57,9 @@ void SignalHandler(const boost::system::error_code& error, int signalNumber); void KeepDatabaseAliveHandler(const boost::system::error_code& error); variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile); -std::unique_ptr<boost::asio::io_service> _ioService; -std::unique_ptr<boost::asio::deadline_timer> _dbPingTimer; -uint32 _dbPingInterval; +static std::unique_ptr<boost::asio::io_service> _ioService; +static std::unique_ptr<boost::asio::deadline_timer> _dbPingTimer; +static uint32 _dbPingInterval; LoginDatabaseWorkerPool LoginDatabase; int main(int argc, char** argv) diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp index 25a9a86bc1b..e0b1ed3b161 100644 --- a/src/server/collision/Management/MMapManager.cpp +++ b/src/server/collision/Management/MMapManager.cpp @@ -177,7 +177,8 @@ namespace MMAP { TC_LOG_ERROR("phase", "MMAP:LoadTile: Bad header in mmap %04u%02i%02i.mmtile", mapId, x, y); fclose(file); - return NULL; + delete pTile; + return nullptr; } if (pTile->fileHeader.mmapVersion != MMAP_VERSION) @@ -185,7 +186,8 @@ namespace MMAP TC_LOG_ERROR("phase", "MMAP:LoadTile: %04u%02i%02i.mmtile was built with generator v%i, expected v%i", mapId, x, y, pTile->fileHeader.mmapVersion, MMAP_VERSION); fclose(file); - return NULL; + delete pTile; + return nullptr; } pTile->data = (unsigned char*)dtAlloc(pTile->fileHeader.size, DT_ALLOC_PERM); @@ -196,7 +198,8 @@ namespace MMAP { TC_LOG_ERROR("phase", "MMAP:LoadTile: Bad header or data in mmap %04u%02i%02i.mmtile", mapId, x, y); fclose(file); - return NULL; + delete pTile; + return nullptr; } fclose(file); @@ -475,7 +478,10 @@ namespace MMAP PhasedTile* pt = new PhasedTile(); // remove old tile if (dtStatusFailed(navMesh->removeTile(loadedTileRefs[packedXY], &pt->data, &pt->dataSize))) + { TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not unload %04u%02i%02i.mmtile from navmesh", _mapId, x, y); + delete pt; + } else { TC_LOG_DEBUG("phase", "MMapData::AddSwap: Unloaded %04u%02i%02i.mmtile from navmesh", _mapId, x, y); diff --git a/src/server/collision/Maps/TileAssembler.cpp b/src/server/collision/Maps/TileAssembler.cpp index 86391d5488a..ce39dc02da8 100644 --- a/src/server/collision/Maps/TileAssembler.cpp +++ b/src/server/collision/Maps/TileAssembler.cpp @@ -24,7 +24,6 @@ #include <set> #include <iomanip> #include <sstream> -#include <iomanip> using G3D::Vector3; using G3D::AABox; diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 91eb00f17c5..3ea18f272ae 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -128,7 +128,7 @@ class UnitAI virtual void InitializeAI() { if (!me->isDead()) Reset(); } - virtual void Reset() { }; + virtual void Reset() { } // Called when unit is charmed virtual void OnCharmed(bool apply) = 0; diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 40ab7ebc52e..6d56774e447 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -847,6 +847,7 @@ class RBACData * @return Success or failure (with reason) to grant the permission * * Example Usage: + * @code * // previously defined "RBACData* rbac" with proper initialization * uint32 permissionId = 2; * if (rbac->GrantRole(permissionId) == RBAC_IN_DENIED_LIST) @@ -870,6 +871,7 @@ class RBACData * @return Success or failure (with reason) to deny the permission * * Example Usage: + * @code * // previously defined "RBACData* rbac" with proper initialization * uint32 permissionId = 2; * if (rbac->DenyRole(permissionId) == RBAC_ID_DOES_NOT_EXISTS) @@ -894,6 +896,7 @@ class RBACData * @return Success or failure (with reason) to remove the permission * * Example Usage: + * @code * // previously defined "RBACData* rbac" with proper initialization * uint32 permissionId = 2; * if (rbac->RevokeRole(permissionId) == RBAC_OK) @@ -984,9 +987,6 @@ class RBACData * * Given a list of permissions, gets all the inherited permissions * @param permissions The list of permissions to expand - * - * @return new list of permissions containing original permissions and - * all other pemissions that are linked to the original ones */ void ExpandPermissions(RBACPermissionContainer& permissions); diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index cfe93b0cde3..9c347879768 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -28,6 +28,7 @@ #include "DBCEnums.h" #include "DisableMgr.h" #include "GameEventMgr.h" +#include "Garrison.h" #include "GridNotifiersImpl.h" #include "Group.h" #include "Guild.h" @@ -1161,6 +1162,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: SetCriteriaProgress(achievementCriteria, 1, referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: @@ -1269,6 +1271,39 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: + case ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED: + case ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES: + case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER: + case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER: + case ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR: + case ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE: + case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET: + case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT: + case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT: + case ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA: + case ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER: + case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING: + case ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING: + case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON: + case ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION: + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT: + case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL: + case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS: break; // Not implemented yet :( } @@ -1413,6 +1448,7 @@ bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteria const* achieveme case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: return progress->counter >= (requiredAmount * 75); @@ -2492,6 +2528,44 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(ModifierTreeNode const* if (!unit || unit->GetHealthPct() >= reqValue) return false; break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY: // 145 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->PacketInfo.Quality != reqValue) + return false; + + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL: // 146 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->PacketInfo.FollowerLevel < reqValue) + return false; + + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL: // 184 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->GetItemLevel() < reqValue) + return false; + break; + } default: break; } @@ -2729,6 +2803,74 @@ char const* AchievementGlobalMgr::GetCriteriaTypeString(AchievementCriteriaTypes return "GUILD_CHALLENGE_TYPE"; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: return "GUILD_CHALLENGE"; + case ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED: + return "LFR_DUNGEONS_COMPLETED"; + case ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES: + return "LFR_LEAVES"; + case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER: + return "LFR_VOTE_KICKS_INITIATED_BY_PLAYER"; + case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER: + return "LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER"; + case ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR: + return "BE_KICKED_FROM_LFR"; + case ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: + return "COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: + return "COMPLETE_SCENARIO_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO: + return "COMPLETE_SCENARIO"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: + return "OWN_BATTLE_PET"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: + return "OWN_BATTLE_PET_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET: + return "CAPTURE_BATTLE_PET"; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE: + return "WIN_PET_BATTLE"; + case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET: + return "LEVEL_BATTLE_PET"; + case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT: + return "CAPTURE_BATTLE_PET_CREDIT"; + case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT: + return "LEVEL_BATTLE_PET_CREDIT"; + case ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA: + return "ENTER_AREA"; + case ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA: + return "LEAVE_AREA"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER: + return "COMPLETE_DUNGEON_ENCOUNTER"; + case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + return "PLACE_GARRISON_BUILDING"; + case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING: + return "UPGRADE_GARRISON_BUILDING"; + case ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING: + return "CONSTRUCT_GARRISON_BUILDING"; + case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON: + return "UPGRADE_GARRISON"; + case ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION: + return "START_GARRISON_MISSION"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT: + return "COMPLETE_GARRISON_MISSION_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION: + return "COMPLETE_GARRISON_MISSION"; + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT: + return "RECRUIT_GARRISON_FOLLOWER_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT: + return "LEARN_GARRISON_BLUEPRINT_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT: + return "COMPLETE_GARRISON_SHIPMENT"; + case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL: + return "RAISE_GARRISON_FOLLOWER_ITEM_LEVEL"; + case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL: + return "RAISE_GARRISON_FOLLOWER_LEVEL"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY: + return "OWN_TOY"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT: + return "OWN_TOY_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: + return "RECRUIT_GARRISON_FOLLOWER"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS: + return "OWN_HEIRLOOMS"; } return "MISSING_TYPE"; } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index c6c46c48f50..f37526ae71b 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -71,7 +71,7 @@ namespace Trinity void do_helper(WorldPacket& data, char const* text) { WorldPackets::Chat::Chat packet; - packet.Initalize(_msgtype, LANG_UNIVERSAL, _source, _source, text); + packet.Initialize(_msgtype, LANG_UNIVERSAL, _source, _source, text); packet.Write(); data = packet.Move(); } @@ -98,7 +98,7 @@ namespace Trinity snprintf(str, 2048, text, arg1str, arg2str); WorldPackets::Chat::Chat packet; - packet.Initalize(_msgtype, LANG_UNIVERSAL, _source, _source, str); + packet.Initialize(_msgtype, LANG_UNIVERSAL, _source, _source, str); packet.Write(); data = packet.Move(); } diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h index 9a65019a390..eb225250a56 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.h +++ b/src/server/game/Battlegrounds/BattlegroundQueue.h @@ -106,7 +106,7 @@ class BattlegroundQueue class SelectionPool { public: - SelectionPool(): PlayerCount(0) { }; + SelectionPool(): PlayerCount(0) { } void Init(); bool AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount); bool KickGroup(uint32 size); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h b/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h index 3694c62d663..8b6f16d1ff9 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h @@ -42,7 +42,7 @@ class BattlegroundBFGScore final : public BattlegroundScore } } - void BuildObjectivesBlock(std::vector<int32>& stats) + void BuildObjectivesBlock(std::vector<int32>& stats) override { stats.push_back(BasesAssaulted); stats.push_back(BasesDefended); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundTP.h b/src/server/game/Battlegrounds/Zones/BattlegroundTP.h index b11485d6025..1dfd3801864 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundTP.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundTP.h @@ -42,7 +42,7 @@ class BattlegroundTPScore final : public BattlegroundScore } } - void BuildObjectivesBlock(std::vector<int32>& stats) + void BuildObjectivesBlock(std::vector<int32>& stats) override { stats.push_back(FlagCaptures); stats.push_back(FlagReturns); diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 04b6eb1b5b1..90c44aa501b 100644 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -626,10 +626,10 @@ void Channel::Say(ObjectGuid const& guid, std::string const& what, uint32 lang) WorldPackets::Chat::Chat packet; if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) - packet.Initalize(CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, _name); + packet.Initialize(CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, _name); else { - packet.Initalize(CHAT_MSG_CHANNEL, Language(lang), nullptr, nullptr, what, 0, _name); + packet.Initialize(CHAT_MSG_CHANNEL, Language(lang), nullptr, nullptr, what, 0, _name); packet.SenderGUID = guid; packet.TargetGUID = guid; } @@ -990,32 +990,42 @@ void Channel::MakeVoiceOff(WorldPackets::Channel::ChannelNotify& data, ObjectGui void Channel::JoinNotify(Player const* player) { ObjectGuid const& guid = player->GetGUID(); - WorldPacket data(IsConstant() ? SMSG_USERLIST_ADD : SMSG_USERLIST_UPDATE, 8 + 1 + 1 + 4 + GetName().size()); - data << guid; - data << uint8(GetPlayerFlags(guid)); - data << uint8(GetFlags()); - data << uint32(GetNumPlayers()); - data << GetName(); if (IsConstant()) - SendToAllButOne(&data, guid); + { + WorldPackets::Channel::UserlistAdd userlistAdd; + userlistAdd.AddedUserGUID = guid; + userlistAdd.ChannelFlags = GetFlags(); + userlistAdd.UserFlags = GetPlayerFlags(guid); + userlistAdd.ChannelID = GetChannelId(); + userlistAdd.ChannelName = GetName(); + SendToAllButOne(userlistAdd.Write(), guid); + } else - SendToAll(&data); + { + WorldPackets::Channel::UserlistUpdate userlistUpdate; + userlistUpdate.UpdatedUserGUID = guid; + userlistUpdate.ChannelFlags = GetFlags(); + userlistUpdate.UserFlags = GetPlayerFlags(guid); + userlistUpdate.ChannelID = GetChannelId(); + userlistUpdate.ChannelName = GetName(); + SendToAll(userlistUpdate.Write()); + } } void Channel::LeaveNotify(Player const* player) { ObjectGuid const& guid = player->GetGUID(); - WorldPacket data(SMSG_USERLIST_REMOVE, 8 + 1 + 4 + GetName().size()); - data << guid; - data << uint8(GetFlags()); - data << uint32(GetNumPlayers()); - data << GetName(); + WorldPackets::Channel::UserlistRemove userlistRemove; + userlistRemove.RemovedUserGUID = guid; + userlistRemove.ChannelFlags = GetFlags(); + userlistRemove.ChannelID = GetChannelId(); + userlistRemove.ChannelName = GetName(); if (IsConstant()) - SendToAllButOne(&data, guid); + SendToAllButOne(userlistRemove.Write(), guid); else - SendToAll(&data); + SendToAll(userlistRemove.Write()); } void Channel::SetModerator(ObjectGuid const& guid, bool set) diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h index 2cfe0797bce..23cd4e4cada 100644 --- a/src/server/game/Chat/Channels/Channel.h +++ b/src/server/game/Chat/Channels/Channel.h @@ -72,7 +72,9 @@ enum ChatNotify CHAT_NOT_IN_AREA_NOTICE = 0x20, //+ "[%s] You are not in the correct area for this channel."; -- The user is trying to send a chat to a zone specific channel, and they're not physically in that zone. CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels. CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s."; - CHAT_VOICE_OFF_NOTICE = 0x23 //+ "[%s] Channel voice disabled by %s."; + CHAT_VOICE_OFF_NOTICE = 0x23, //+ "[%s] Channel voice disabled by %s."; + CHAT_TRIAL_RESTRICTED = 0x24, + CHAT_NOT_ALLOWED_IN_CHANNEL = 0x25 }; enum ChannelFlags @@ -206,7 +208,7 @@ class Channel void DeVoice(Player const* player); void JoinNotify(Player const* player); void LeaveNotify(Player const* player); - void SetOwnership(bool ownership) { _ownership = ownership; }; + void SetOwnership(bool ownership) { _ownership = ownership; } static void CleanOldChannelsInDB(); private: diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index c7952d7758c..ed6aa52da5a 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -201,7 +201,7 @@ void ChatHandler::SendSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); m_session->SendPacket(packet.Write()); } @@ -219,7 +219,7 @@ void ChatHandler::SendGlobalSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); sWorld->SendGlobalMessage(packet.Write()); } @@ -237,7 +237,7 @@ void ChatHandler::SendGlobalGMSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); sWorld->SendGlobalGMMessage(packet.Write()); } diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index fc05f0fdc6a..719e539a9c4 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -159,6 +159,12 @@ enum AchievementCriteriaAdditionalCondition ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND = 63, // NYI ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RARITY = 65, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RACE = 66, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY = 145, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL = 146, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_RARE_MISSION = 147, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_LEVEL = 149, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_MISSION_TYPE = 167, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL = 184, }; enum AchievementCriteriaFlags @@ -188,121 +194,169 @@ enum AchievementCriteriaTimedTypes 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, - ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16, - ACHIEVEMENT_CRITERIA_TYPE_DEATH = 17, - ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19, - ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20, - ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER = 23, - ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24, - ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27, - ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28, - ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29, - ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30, - ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31, - ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32, - ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34, - ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL = 35, - ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36, - ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40, - ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42, - ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43, - ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44, - ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION = 47, - ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48, - ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50, /// @todo itemlevel is mentioned in text but not present in dbc - ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51, - ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52, - ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53, - ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54, - ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55, - ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56, /// @todo in some cases map not present, and in some cases need do without die - ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57, - ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS = 59, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS = 60, - ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS = 61, - ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD = 62, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING = 63, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER = 65, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL = 66, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67, - ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68, - ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69, - ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70, - ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72, + 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, + ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16, + ACHIEVEMENT_CRITERIA_TYPE_DEATH = 17, + ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19, + ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20, + ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER = 23, + ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24, + ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27, + ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28, + ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29, + ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30, + ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31, + ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32, + ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33, + ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34, + ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL = 35, + ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36, + ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39, + ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40, + ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41, + ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42, + ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43, + ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44, + ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45, + ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46, + ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION = 47, + ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48, + ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49, + ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50, /// @todo itemlevel is mentioned in text but not present in dbc + ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51, + ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52, + ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53, + ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54, + ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55, + ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56, /// @todo in some cases map not present, and in some cases need do without die + ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57, + ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS = 59, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS = 60, + ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS = 61, + ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD = 62, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING = 63, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER = 65, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL = 66, + ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67, + ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68, + ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69, + ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70, + ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72, /// @todo 73: Achievements 1515, 1241, 1103 (Name: Mal'Ganis) - ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN = 74, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75, - ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76, - ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL = 77, - ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE = 78, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS = 80, - ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION = 82, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID = 83, - ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS = 84, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD = 85, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED = 86, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION = 87, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION = 88, - ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS = 89, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM = 90, - ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM = 91, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED = 93, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED = 94, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT = 101, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED = 102, - ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED = 103, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST = 104, - ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED = 105, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED = 106, - ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED = 107, - ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN = 108, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109, - ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110, /// @todo target entry is missing - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112, - ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113, - 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 188 + ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN = 74, + ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75, + ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76, + ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL = 77, + ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE = 78, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS = 80, + ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION = 82, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID = 83, + ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS = 84, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD = 85, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED = 86, + ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION = 87, + ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION = 88, + ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS = 89, + ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM = 90, + ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM = 91, + ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED = 93, + ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED = 94, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT = 101, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED = 102, + ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED = 103, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST = 104, + ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED = 105, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED = 106, + ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED = 107, + ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN = 108, + ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109, + ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110, /// @todo target entry is missing + ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112, + ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113, + 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 + // 140 unk + // 141 unk + // 142 unk + // 143 unk + // 144 unk + ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED = 145, + ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES = 146, + ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER = 147, + ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER = 148, + ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR = 149, + ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK = 150, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT = 151, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO = 152, + // ACHIEVEMENT_CRITERIA_TYPE_REACH_SOMETHING_LIKE_AREATRIGGER = 153, + // 154 + ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET = 155, + ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT = 156, + ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET = 157, + ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE = 158, + // 159 + ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET = 160, + ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT = 161, // triggers a quest credit + ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT = 162, // triggers a quest credit + ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA = 163, // triggers a quest credit + ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA = 164, // triggers a quest credit + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER = 165, + ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING = 167, + ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING = 168, + ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING = 169, + ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON = 170, + ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION = 171, + // 172 + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT = 173, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION = 174, + ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT = 175, + // 176 + // 177 + ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT = 178, + // 179 + // 180 + // 181 + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT = 182, + ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL = 183, + ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL = 184, + ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY = 185, + ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT = 186, + ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER = 187, + ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS = 189 +}; + +#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 190 enum AchievementCriteriaTreeOperator { diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index e1f0c595b5f..540d4cf6d9e 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -60,6 +60,7 @@ static AreaFlagByMapID sAreaFlagByMapID; // for instances wit static WMOAreaInfoByTripple sWMOAreaInfoByTripple; DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt); +DBCStorage <AnimKitEntry> sAnimKitStore(AnimKitfmt); DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt); DBCStorage <ArmorLocationEntry> sArmorLocationStore(ArmorLocationfmt); DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt); @@ -369,6 +370,7 @@ void LoadDBCStores(const std::string& dataPath) } LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc"/*, &CustomAchievementfmt, &CustomAchievementIndex*/);//19116 + LoadDBC(availableDbcLocales, bad_dbc_files, sAnimKitStore, dbcPath, "AnimKit.dbc");//19865 LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sAuctionHouseStore, dbcPath, "AuctionHouse.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sArmorLocationStore, dbcPath, "ArmorLocation.dbc");//19116 @@ -881,9 +883,9 @@ void Map2ZoneCoordinates(float& x, float& y, uint32 zone) std::swap(x, y); // client have map coords swapped } -MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapID) +MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapId, Difficulty* difficulty /*= nullptr*/) { - auto itr = sMapDifficultyMap.find(mapID); + auto itr = sMapDifficultyMap.find(mapId); if (itr == sMapDifficultyMap.end()) return nullptr; @@ -892,14 +894,22 @@ MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapID) for (auto& p : itr->second) { - DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(p.first); - if (!difficulty) + DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(p.first); + if (!difficultyEntry) continue; - if (difficulty->Flags & DIFFICULTY_FLAG_DEFAULT) + if (difficultyEntry->Flags & DIFFICULTY_FLAG_DEFAULT) + { + if (difficulty) + *difficulty = Difficulty(p.first); + return p.second; + } } + if (difficulty) + *difficulty = Difficulty(itr->second.begin()->first); + return itr->second.begin()->second; } @@ -920,7 +930,7 @@ MapDifficultyEntry const* GetDownscaledMapDifficultyData(uint32 mapId, Difficult { DifficultyEntry const* diffEntry = sDifficultyStore.LookupEntry(difficulty); if (!diffEntry) - return GetDefaultMapDifficulty(mapId); + return GetDefaultMapDifficulty(mapId, &difficulty); uint32 tmpDiff = difficulty; MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); @@ -929,7 +939,7 @@ MapDifficultyEntry const* GetDownscaledMapDifficultyData(uint32 mapId, Difficult tmpDiff = diffEntry->FallbackDifficultyID; diffEntry = sDifficultyStore.LookupEntry(tmpDiff); if (!diffEntry) - return GetDefaultMapDifficulty(mapId); + return GetDefaultMapDifficulty(mapId, &difficulty); // pull new data mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); // we are 10 normal or 25 normal diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 72c0c35f1cb..5ad47549351 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -66,7 +66,7 @@ void Zone2MapCoordinates(float &x, float &y, uint32 zone); void Map2ZoneCoordinates(float &x, float &y, uint32 zone); typedef std::unordered_map<uint32, std::unordered_map<uint32, MapDifficultyEntry const*>> MapDifficultyMap; -MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapID); +MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapId, Difficulty* difficulty = nullptr); MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); MapDifficultyEntry const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty); @@ -123,6 +123,7 @@ private: }; extern DBCStorage <AchievementEntry> sAchievementStore; +extern DBCStorage <AnimKitEntry> sAnimKitStore; extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore; extern DBCStorage <ArmorLocationEntry> sArmorLocationStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 2893ea3df83..f8f140ff02b 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -50,12 +50,12 @@ struct AchievementEntry uint32 CriteriaTree; // 14 }; -struct AchievementCategoryEntry +struct AnimKitEntry { uint32 ID; // 0 - uint32 Parent; // 1 -1 for main category - //char* Name_lang; // 2 - //uint32 UIOrder; // 3 + //uint32 OneShotDuration; // 1 + //uint32 OneShotStopAnimKitID; // 2 + //uint32 LowDefAnimKitID; // 3 }; // Temporary define until max depth is found somewhere (adt?) @@ -494,12 +494,15 @@ struct CriteriaEntry uint32 ObjectiveId; // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 + // ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA = 163 + // ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA = 164 uint32 AreaID; // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36 // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41 // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42 // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57 + // ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY = 185 uint32 ItemID; // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 @@ -544,6 +547,21 @@ struct CriteriaEntry // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109 uint32 LootType; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER = 165 + uint32 DungeonEncounterID; + + // ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING = 169 + uint32 GarrBuildingID; + + // ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON = 170 + uint32 GarrisonLevel; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION = 174 + uint32 GarrMissionID; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT = 182 + uint32 CharShipmentContainerID; } Asset; // 2 uint32 StartEvent; // 3 uint32 StartAsset; // 4 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index e3b474bc27b..a67ec26ed7c 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -25,6 +25,7 @@ char const Achievementfmt[] = "niixsxiixixxiii"; const std::string CustomAchievementfmt = "pppaaaapapaapp"; const std::string CustomAchievementIndex = "ID"; +char const AnimKitfmt[] = "nxxx"; char const AreaTableEntryfmt[] = "iiiniixxxxxxisiiiiixxxxxxxxxx"; char const AreaTriggerEntryfmt[] = "nifffxxxfffffxxxx"; char const ArmorLocationfmt[] = "nfffff"; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index b077f3e6110..e786c3b9c7c 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -412,7 +412,7 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const joinData.result = LFG_JOIN_NOT_MEET_REQS; else if (grp) { - if (grp->GetMembersCount() > MAXGROUPSIZE) + if (grp->GetMembersCount() > MAX_GROUP_SIZE) joinData.result = LFG_JOIN_TOO_MUCH_MEMBERS; else { diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index 97f87a4d814..30e9a587353 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -323,7 +323,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) LfgRolesMap proposalRoles; // Check for correct size - if (check.size() > MAXGROUPSIZE || check.empty()) + if (check.size() > MAX_GROUP_SIZE || check.empty()) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s): Size wrong - Not compatibles", strGuids.c_str()); return LFG_INCOMPATIBLES_WRONG_GROUP_SIZE; @@ -349,7 +349,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) // Check if more than one LFG group and number of players joining uint8 numPlayers = 0; uint8 numLfgGroups = 0; - for (GuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it) + for (GuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAX_GROUP_SIZE; ++it) { ObjectGuid guid = *it; LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(guid); @@ -374,8 +374,8 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) } } - // Group with less that MAXGROUPSIZE members always compatible - if (check.size() == 1 && numPlayers != MAXGROUPSIZE) + // Group with less that MAX_GROUP_SIZE members always compatible + if (check.size() == 1 && numPlayers != MAX_GROUP_SIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) single group. Compatibles", strGuids.c_str()); LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(check.front()); @@ -396,7 +396,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) return LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS; } - if (numPlayers > MAXGROUPSIZE) + if (numPlayers > MAX_GROUP_SIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Too much players (%u)", strGuids.c_str(), numPlayers); SetCompatibles(strGuids, LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS); @@ -473,7 +473,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) } // Enough players? - if (numPlayers != MAXGROUPSIZE) + if (numPlayers != MAX_GROUP_SIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Compatibles but not enough players(%u)", strGuids.c_str(), numPlayers); LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS); diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 815c98c9710..faa458d45dc 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -505,7 +505,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const packet.Info.SuggestedGroupNum = quest->GetSuggestedPlayers(); packet.Info.RewardNextQuest = quest->GetNextQuestInChain(); packet.Info.RewardXPDifficulty = quest->GetXPDifficulty(); - packet.Info.Float10 = quest->Float10; // Unk + packet.Info.RewardXPMultiplier = quest->GetXPMultiplier(); packet.Info.Float13 = quest->Float13; // Unk if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 852269855df..da2257641d5 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -180,7 +180,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u m_stationaryPosition.Relocate(x, y, z, ang); if (!IsPositionValid()) { - TC_LOG_ERROR("misc", "Gameobject (GUID: " UI64FMTD " Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, name_id, x, y); + TC_LOG_ERROR("misc", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, GetSpawnId(), name_id, x, y); return false; } @@ -195,13 +195,13 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(name_id); if (!goinfo) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", guidlow, name_id, map->GetId(), x, y, z); + TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", guidlow, GetSpawnId(), name_id, map->GetId(), x, y, z); return false; } if (goinfo->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", guidlow, name_id); + TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", guidlow, GetSpawnId(), name_id); return false; } @@ -214,7 +214,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u if (goinfo->type >= MAX_GAMEOBJECT_TYPE) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guidlow, name_id, goinfo->type); + TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guidlow, GetSpawnId(), name_id, goinfo->type); return false; } @@ -310,7 +310,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u break; } - if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(guidlow)) + if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(GetSpawnId())) { if (addon->InvisibilityValue) { @@ -2163,7 +2163,7 @@ void GameObject::SetTransportState(GOState state, uint32 stopFrame /*= 0*/) m_goValue.Transport.StateUpdateTimer = 0; m_goValue.Transport.PathProgress = getMSTime(); if (GetGoState() >= GO_STATE_TRANSPORT_STOPPED) - m_goValue.Transport.StopFrames->at(GetGoState() - GO_STATE_TRANSPORT_STOPPED); + m_goValue.Transport.PathProgress += m_goValue.Transport.StopFrames->at(GetGoState() - GO_STATE_TRANSPORT_STOPPED); SetGoState(GO_STATE_TRANSPORT_ACTIVE); } else diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index c2f7718438e..655af613220 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -212,11 +212,16 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c break; } - if (!(flags & UPDATEFLAG_LIVING)) - if (WorldObject const* worldObject = dynamic_cast<WorldObject const*>(this)) + if (WorldObject const* worldObject = dynamic_cast<WorldObject const*>(this)) + { + if (!(flags & UPDATEFLAG_LIVING)) if (!worldObject->m_movementInfo.transport.guid.IsEmpty()) flags |= UPDATEFLAG_TRANSPORT_POSITION; + if (worldObject->GetAIAnimKitId() || worldObject->GetMovementAnimKitId() || worldObject->GetMeleeAnimKitId()) + flags |= UPDATEFLAG_ANIMKITS; + } + if (flags & UPDATEFLAG_STATIONARY_POSITION) { // UPDATETYPE_CREATE_OBJECT2 for some gameobject types... @@ -237,14 +242,9 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c } if (Unit const* unit = ToUnit()) - { if (unit->GetVictim()) flags |= UPDATEFLAG_HAS_TARGET; - if (unit->GetAIAnimKitId() || unit->GetMovementAnimKitId() || unit->GetMeleeAnimKitId()) - flags |= UPDATEFLAG_ANIMKITS; - } - ByteBuffer buf(0x400); buf << uint8(updateType); buf << GetPackGUID(); @@ -502,10 +502,10 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const if (AnimKitCreate) { - Unit const* unit = ToUnit(); - *data << uint16(unit->GetAIAnimKitId()); // AiID - *data << uint16(unit->GetMovementAnimKitId()); // MovementID - *data << uint16(unit->GetMeleeAnimKitId()); // MeleeID + WorldObject const* self = static_cast<WorldObject const*>(this); + *data << uint16(self->GetAIAnimKitId()); // AiID + *data << uint16(self->GetMovementAnimKitId()); // MovementID + *data << uint16(self->GetMeleeAnimKitId()); // MeleeID } if (Rotation) @@ -1446,7 +1446,9 @@ void MovementInfo::OutDebug() WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0), m_name(""), m_isActive(false), m_isWorldObject(isWorldObject), m_zoneScript(NULL), m_transport(NULL), m_currMap(NULL), m_InstanceId(0), -m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0) +m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0), +m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0) + { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); @@ -3100,6 +3102,54 @@ ObjectGuid WorldObject::GetTransGUID() const return ObjectGuid::Empty; } +void WorldObject::SetAIAnimKitId(uint16 animKitId) +{ + if (m_aiAnimKitId == animKitId) + return; + + if (animKitId && !sAnimKitStore.LookupEntry(animKitId)) + return; + + m_aiAnimKitId = animKitId; + + WorldPacket data(SMSG_SET_AI_ANIM_KIT, 8 + 2); + data << GetPackGUID(); + data << uint16(animKitId); + SendMessageToSet(&data, true); +} + +void WorldObject::SetMovementAnimKitId(uint16 animKitId) +{ + if (m_movementAnimKitId == animKitId) + return; + + if (animKitId && !sAnimKitStore.LookupEntry(animKitId)) + return; + + m_movementAnimKitId = animKitId; + + WorldPacket data(SMSG_SET_MOVEMENT_ANIM_KIT, 8 + 2); + data << GetPackGUID(); + data << uint16(animKitId); + SendMessageToSet(&data, true); +} + +void WorldObject::SetMeleeAnimKitId(uint16 animKitId) +{ + if (m_meleeAnimKitId == animKitId) + return; + + if (animKitId && !sAnimKitStore.LookupEntry(animKitId)) + return; + + m_meleeAnimKitId = animKitId; + + WorldPacket data(SMSG_SET_MELEE_ANIM_KIT, 8 + 2); + data << GetPackGUID(); + data << uint16(animKitId); + SendMessageToSet(&data, true); +} + void WorldObject::RebuildTerrainSwaps() { // Clear all terrain swaps, will be rebuilt below diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index b4b66bd5121..b9a6320a835 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -649,6 +649,13 @@ class WorldObject : public Object, public WorldLocation virtual float GetStationaryZ() const { return GetPositionZ(); } virtual float GetStationaryO() const { return GetOrientation(); } + uint16 GetAIAnimKitId() const { return m_aiAnimKitId; } + void SetAIAnimKitId(uint16 animKitId); + uint16 GetMovementAnimKitId() const { return m_movementAnimKitId; } + void SetMovementAnimKitId(uint16 animKitId); + uint16 GetMeleeAnimKitId() const { return m_meleeAnimKitId; } + void SetMeleeAnimKitId(uint16 animKitId); + protected: std::string m_name; bool m_isActive; @@ -689,6 +696,10 @@ class WorldObject : public Object, public WorldLocation bool CanDetect(WorldObject const* obj, bool ignoreStealth) const; bool CanDetectInvisibilityOf(WorldObject const* obj) const; bool CanDetectStealthOf(WorldObject const* obj) const; + + uint16 m_aiAnimKitId; + uint16 m_movementAnimKitId; + uint16 m_meleeAnimKitId; }; namespace Trinity diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 05d649fe632..c8152e3ac36 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -39,8 +39,8 @@ Pet::Pet(Player* owner, PetType type) : Guardian(NULL, owner, true), m_usedTalentCount(0), m_removed(false), - m_petType(type), m_duration(0), m_auraRaidUpdateMask(0), m_loading(false), - m_declinedname(NULL) + m_petType(type), m_duration(0), m_loading(false), m_declinedname(NULL), + m_groupUpdateMask(0) { ASSERT(GetOwner()); @@ -337,8 +337,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c owner->PetSpellInitialize(); - if (owner->GetGroup()) - owner->SetGroupUpdateFlag(GROUP_UPDATE_PET); + SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); // TODO: 6.x remove/update pet talents //owner->SendTalentsInfoData(true); @@ -1938,6 +1937,21 @@ void Pet::SetDisplayId(uint32 modelId) if (!isControlled()) return; + SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); +} + +void Pet::SetGroupUpdateFlag(uint32 flag) +{ + if (GetOwner()->GetGroup()) + { + m_groupUpdateMask |= flag; + GetOwner()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET); + } +} + +void Pet::ResetGroupUpdateFlag() +{ + m_groupUpdateMask = GROUP_UPDATE_FLAG_PET_NONE; if (GetOwner()->GetGroup()) - GetOwner()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); + GetOwner()->RemoveGroupUpdateFlag(GROUP_UPDATE_FLAG_PET); } diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index 494db54208d..70f14fbd7ca 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -134,9 +134,9 @@ class Pet : public Guardian uint32 m_usedTalentCount; - uint64 GetAuraUpdateMaskForRaid() const { return m_auraRaidUpdateMask; } - void SetAuraUpdateMaskForRaid(uint8 slot) { m_auraRaidUpdateMask |= (uint64(1) << slot); } - void ResetAuraUpdateMaskForRaid() { m_auraRaidUpdateMask = 0; } + uint32 GetGroupUpdateFlag() const { return m_groupUpdateMask; } + void SetGroupUpdateFlag(uint32 flag); + void ResetGroupUpdateFlag(); DeclinedName const* GetDeclinedNames() const { return m_declinedname; } @@ -147,9 +147,9 @@ class Pet : public Guardian protected: PetType m_petType; int32 m_duration; // time until unsummon (used mostly for summoned guardians and not used for controlled pets) - uint64 m_auraRaidUpdateMask; bool m_loading; uint32 m_regenTimer; + uint32 m_groupUpdateMask; DeclinedName *m_declinedname; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a3a602d2f4a..96e58f41fc6 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -100,6 +100,7 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "WorldStatePackets.h" +#include "InstancePackets.h" #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) @@ -701,7 +702,6 @@ Player::Player(WorldSession* session): Unit(true) // group is initialized in the reference constructor SetGroupInvite(NULL); m_groupUpdateMask = 0; - m_auraRaidUpdateMask = 0; m_bPassOnGroupLoot = false; duel = NULL; @@ -802,7 +802,7 @@ Player::Player(WorldSession* session): Unit(true) m_dungeonDifficulty = DIFFICULTY_NORMAL; m_raidDifficulty = DIFFICULTY_NORMAL_RAID; m_legacyRaidDifficulty = DIFFICULTY_10_N; - m_raidMapDifficulty = DIFFICULTY_NORMAL_RAID; + m_prevMapDifficulty = DIFFICULTY_NORMAL_RAID; m_lastPotionId = 0; _talentMgr = new PlayerTalentInfo(); @@ -887,7 +887,6 @@ Player::Player(WorldSession* session): Unit(true) _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); @@ -927,9 +926,6 @@ Player::~Player() 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(); @@ -1125,10 +1121,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac UpdateMaxHealth(); // Update max Health (for add bonus from stamina) SetFullHealth(); if (getPowerType() == POWER_MANA) - { - UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intellect) SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); - } if (getPowerType() == POWER_RUNIC_POWER) { @@ -4594,6 +4587,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS); + stmt->setUInt64(0, guid); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); sWorld->DeleteCharacterInfo(playerguid); @@ -7387,7 +7384,11 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) // group update if (GetGroup()) + { SetGroupUpdateFlag(GROUP_UPDATE_FULL); + if (Pet* pet = GetPet()) + pet->SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); + } m_zoneUpdateId = newZone; m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; @@ -7698,23 +7699,23 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) break; case ITEM_MOD_AGILITY: // modify agility HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_STRENGTH: //modify strength HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STRENGTH, float(val), apply); + ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_INTELLECT: //modify intellect HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_INTELLECT, float(val), apply); + ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_SPIRIT: //modify spirit HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_SPIRIT, float(val), apply); + ApplyStatBuffMod(STAT_SPIRIT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_SPIRIT, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_STAMINA: //modify stamina HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STAMINA, float(val), apply); + ApplyStatBuffMod(STAT_STAMINA, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STAMINA, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply); @@ -7847,6 +7848,32 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) case ITEM_MOD_ARCANE_RESISTANCE: HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(val), apply); break; + case ITEM_MOD_AGI_STR_INT: + HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + break; + case ITEM_MOD_AGI_STR: + HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); + break; + case ITEM_MOD_AGI_INT: + HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + break; + case ITEM_MOD_STR_INT: + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + break; } } @@ -17344,18 +17371,19 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) _LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES)); - m_achievementMgr->CheckAllAchievementCriteria(this); - _LoadEquipmentSets(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS)); _LoadCUFProfiles(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES)); - std::unique_ptr<Garrison> garrison(new Garrison(this)); + std::unique_ptr<Garrison> garrison = Trinity::make_unique<Garrison>(this); if (garrison->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS), - holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS))) + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES))) _garrison = std::move(garrison); + m_achievementMgr->CheckAllAchievementCriteria(this); return true; } @@ -17369,19 +17397,19 @@ void Player::_LoadCUFProfiles(PreparedQueryResult result) // 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(); + 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 topPoint = fields[7].GetUInt8(); + uint8 bottomPoint = fields[8].GetUInt8(); + uint8 leftPoint = fields[9].GetUInt8(); + uint16 topOffset = fields[10].GetUInt16(); + uint16 bottomOffset = fields[11].GetUInt16(); + uint16 leftOffset = fields[12].GetUInt16(); if (id > MAX_CUF_PROFILES) { @@ -17389,7 +17417,7 @@ void Player::_LoadCUFProfiles(PreparedQueryResult result) continue; } - _CUFProfiles[id] = new CUFProfile(name, frameHeight, frameWidth, sortBy, healthText, boolOptions, unk146, unk147, unk148, unk150, unk152, unk154); + _CUFProfiles[id] = Trinity::make_unique<CUFProfile>(name, frameHeight, frameWidth, sortBy, healthText, boolOptions, topPoint, bottomPoint, leftPoint, topOffset, bottomOffset, leftOffset); } while (result->NextRow()); } @@ -18557,12 +18585,7 @@ void Player::SetPendingBind(uint32 instanceId, uint32 bindTimer) void Player::SendRaidInfo() { - uint32 counter = 0; - - WorldPacket data(SMSG_INSTANCE_INFO, 4); - - size_t p_counter = data.wpos(); - data << uint32(counter); // placeholder + WorldPackets::Instance::InstanceInfo instanceInfo; time_t now = time(NULL); @@ -18573,27 +18596,28 @@ void Player::SendRaidInfo() if (itr->second.perm) { InstanceSave* save = itr->second.save; - bool isHeroic = save->GetDifficultyID() == DIFFICULTY_10_HC || save->GetDifficultyID() == DIFFICULTY_25_HC; - uint32 completedEncounters = 0; + + WorldPackets::Instance::InstanceLockInfos lockInfos; + + lockInfos.InstanceID = save->GetInstanceId(); + lockInfos.MapID = save->GetMapId(); + lockInfos.DifficultyID = save->GetDifficultyID(); + lockInfos.TimeRemaining = save->GetResetTime() - now; + + lockInfos.CompletedMask = 0; if (Map* map = sMapMgr->FindMap(save->GetMapId(), save->GetInstanceId())) if (InstanceScript* instanceScript = ((InstanceMap*)map)->GetInstanceScript()) - completedEncounters = instanceScript->GetCompletedEncounterMask(); + lockInfos.CompletedMask = instanceScript->GetCompletedEncounterMask(); + + lockInfos.Locked = lockInfos.TimeRemaining <= 0; + lockInfos.Extended = false; - data << uint32(save->GetMapId()); // map id - data << uint32(save->GetDifficultyID()); // 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; + instanceInfo.LockList.push_back(lockInfos); } } } - data.put<uint32>(p_counter, counter); - GetSession()->SendPacket(&data); + GetSession()->SendPacket(instanceInfo.Write()); } /// convert the player's binds to the group @@ -19418,13 +19442,13 @@ void Player::_SaveCUFProfiles(SQLTransaction& trans) 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); + stmt->setUInt32(7, _CUFProfiles[i]->BoolOptions.to_ulong()); // 25 of 32 fields used, fits in an int + stmt->setUInt8(8, _CUFProfiles[i]->TopPoint); + stmt->setUInt8(9, _CUFProfiles[i]->BottomPoint); + stmt->setUInt8(10, _CUFProfiles[i]->LeftPoint); + stmt->setUInt16(11, _CUFProfiles[i]->TopOffset); + stmt->setUInt16(12, _CUFProfiles[i]->BottomOffset); + stmt->setUInt16(13, _CUFProfiles[i]->LeftOffset); } trans->Append(stmt); @@ -19966,10 +19990,10 @@ void Player::SendExplorationExperience(uint32 Area, uint32 Experience) GetSession()->SendPacket(WorldPackets::Misc::ExplorationExperience(Experience, Area).Write()); } -void Player::SendDungeonDifficulty() +void Player::SendDungeonDifficulty(int32 forcedDifficulty /*= -1*/) { WorldPackets::Misc::DungeonDifficultySet dungeonDifficultySet; - dungeonDifficultySet.DifficultyID = GetDungeonDifficultyID(); + dungeonDifficultySet.DifficultyID = forcedDifficulty == -1 ? GetDungeonDifficultyID() : forcedDifficulty; GetSession()->SendPacket(dungeonDifficultySet.Write()); } @@ -20220,7 +20244,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) GetSession()->SendPacket(&data); if (GetGroup()) - SetGroupUpdateFlag(GROUP_UPDATE_PET); + SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET); } } @@ -20259,7 +20283,7 @@ void Player::Say(std::string const& text, Language language, WorldObject const* sScriptMgr->OnPlayerChat(this, CHAT_MSG_SAY, language, _text); WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_SAY, language, this, this, _text); + packet.Initialize(CHAT_MSG_SAY, language, this, this, _text); SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); } @@ -20269,7 +20293,7 @@ void Player::Yell(std::string const& text, Language language, WorldObject const* sScriptMgr->OnPlayerChat(this, CHAT_MSG_YELL, language, _text); WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_YELL, language, this, this, _text); + packet.Initialize(CHAT_MSG_YELL, language, this, this, _text); SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true); } @@ -20279,7 +20303,7 @@ void Player::TextEmote(std::string const& text, WorldObject const* /*= nullptr*/ sScriptMgr->OnPlayerChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text); WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text); + packet.Initialize(CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text); SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)); } @@ -20292,7 +20316,7 @@ void Player::WhisperAddon(std::string const& text, const std::string& prefix, Pl return; WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_WHISPER, LANG_ADDON, this, this, text, 0, "", DEFAULT_LOCALE, prefix); + packet.Initialize(CHAT_MSG_WHISPER, LANG_ADDON, this, this, text, 0, "", DEFAULT_LOCALE, prefix); receiver->SendDirectMessage(packet.Write()); } @@ -20309,14 +20333,14 @@ void Player::Whisper(std::string const& text, Language language, Player* target, sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, language, _text, target); WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_WHISPER, Language(language), this, this, _text); + packet.Initialize(CHAT_MSG_WHISPER, Language(language), this, this, _text); target->SendDirectMessage(packet.Write()); // rest stuff shouldn't happen in case of addon message if (isAddonMessage) return; - packet.Initalize(CHAT_MSG_WHISPER_INFORM, Language(language), target, target, _text); + packet.Initialize(CHAT_MSG_WHISPER_INFORM, Language(language), target, target, _text); SendDirectMessage(packet.Write()); if (!isAcceptWhispers() && !IsGameMaster() && !target->IsGameMaster()) @@ -22618,11 +22642,20 @@ void Player::SendInitialPacketsAfterAddToMap() if (GetMap()->IsRaid()) { - DifficultyEntry const* difficulty = sDifficultyStore.AssertEntry(GetMap()->GetDifficultyID()); - SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0, GetMap()->GetDifficultyID()); + m_prevMapDifficulty = GetMap()->GetDifficultyID(); + DifficultyEntry const* difficulty = sDifficultyStore.AssertEntry(m_prevMapDifficulty); + SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0, m_prevMapDifficulty); } else if (GetMap()->IsNonRaidDungeon()) - SendDungeonDifficulty(); + { + m_prevMapDifficulty = GetMap()->GetDifficultyID(); + SendDungeonDifficulty(m_prevMapDifficulty); + } + else if (!GetMap()->Instanceable()) + { + DifficultyEntry const* difficulty = sDifficultyStore.AssertEntry(m_prevMapDifficulty); + SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0); + } if (_garrison) _garrison->SendRemoteInfo(); @@ -22636,9 +22669,8 @@ void Player::SendUpdateToOutOfRangeGroupMembers() group->UpdatePlayerOutOfRange(this); m_groupUpdateMask = GROUP_UPDATE_FLAG_NONE; - m_auraRaidUpdateMask = 0; if (Pet* pet = GetPet()) - pet->ResetAuraUpdateMaskForRaid(); + pet->ResetGroupUpdateFlag(); } void Player::SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg) @@ -22697,10 +22729,10 @@ void Player::ApplyEquipCooldown(Item* pItem) GetSpellHistory()->AddCooldown(effectData->SpellID, pItem->GetEntry(), std::chrono::seconds(30)); - WorldPacket data(SMSG_ITEM_COOLDOWN, 12); - data << pItem->GetGUID(); - data << uint32(effectData->SpellID); - GetSession()->SendPacket(&data); + WorldPackets::Item::ItemCooldown data; + data.ItemGuid = pItem->GetGUID(); + data.SpellID = effectData->SpellID; + GetSession()->SendPacket(data.Write()); } } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index df08a1b30d4..5bae50edb68 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -207,8 +207,9 @@ enum CUFBoolOptions CUF_DISPLAY_POWER_BAR, CUF_DISPLAY_BORDER, CUF_USE_CLASS_COLORS, - CUF_DISPLAY_NON_BOSS_DEBUFFS, CUF_DISPLAY_HORIZONTAL_GROUPS, + CUF_DISPLAY_NON_BOSS_DEBUFFS, + CUF_DYNAMIC_POSITION, CUF_LOCKED, CUF_SHOWN, CUF_AUTO_ACTIVATE_2_PLAYERS, @@ -222,9 +223,6 @@ enum CUFBoolOptions 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 @@ -236,32 +234,32 @@ 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; + FrameHeight = 0; + FrameWidth = 0; + SortBy = 0; + HealthText = 0; + TopPoint = 0; + BottomPoint = 0; + LeftPoint = 0; + TopOffset = 0; + BottomOffset = 0; + LeftOffset = 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) + uint8 topPoint, uint8 bottomPoint, uint8 leftPoint, uint16 topOffset, uint16 bottomOffset, uint16 leftOffset) : 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; + FrameHeight = frameHeight; + FrameWidth = frameWidth; + SortBy = sortBy; + HealthText = healthText; + TopPoint = topPoint; + BottomPoint = bottomPoint; + LeftPoint = leftPoint; + TopOffset = topOffset; + BottomOffset = bottomOffset; + LeftOffset = leftOffset; } std::string ProfileName; @@ -270,15 +268,15 @@ struct CUFProfile uint8 SortBy; uint8 HealthText; - // LeftAlign, TopAlight, BottomAllign (unk order) - uint8 Unk146; - uint8 Unk147; - uint8 Unk148; + // LeftAlign, TopAlight, BottomAlign + uint8 TopPoint; + uint8 BottomPoint; + uint8 LeftPoint; - // LeftOffset, TopOffset and BottomOffset (unk order) - uint16 Unk150; - uint16 Unk152; - uint16 Unk154; + // LeftOffset, TopOffset and BottomOffset + uint16 TopOffset; + uint16 BottomOffset; + uint16 LeftOffset; std::bitset<CUF_BOOL_OPTIONS_COUNT> BoolOptions; @@ -486,9 +484,9 @@ struct Runes struct EnchantDuration { - EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { }; + EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { } EnchantDuration(Item* _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot), - leftduration(_leftduration){ ASSERT(item); }; + leftduration(_leftduration){ ASSERT(item); } Item* item; EnchantmentSlot slot; @@ -989,6 +987,8 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_GARRISON, PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS, PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS, + PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS, + PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES, MAX_PLAYER_LOGIN_QUERY }; @@ -1737,8 +1737,9 @@ 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 + void SaveCUFProfile(uint8 id, std::nullptr_t) { _CUFProfiles[id] = nullptr; } ///> Empties a CUF profile at position 0-4 + void SaveCUFProfile(uint8 id, std::unique_ptr<CUFProfile> profile) { _CUFProfiles[id] = std::move(profile); } ///> Replaces a CUF profile at position 0-4 + CUFProfile* GetCUFProfile(uint8 id) const { return _CUFProfiles[id].get(); } ///> Retrieves a CUF profile at position 0-4 uint8 GetCUFProfilesCount() const { uint8 count = 0; @@ -2056,7 +2057,6 @@ class Player : public Unit, public GridObject<Player> uint32 GetSpellByProto(ItemTemplate* proto); float GetHealthBonusFromStamina(); - float GetManaBonusFromIntellect(); bool UpdateStats(Stats stat) override; bool UpdateAllStats() override; @@ -2132,7 +2132,7 @@ class Player : public Unit, public GridObject<Player> void SendAutoRepeatCancel(Unit* target); void SendExplorationExperience(uint32 Area, uint32 Experience); - void SendDungeonDifficulty(); + void SendDungeonDifficulty(int32 forcedDifficulty = -1); void SendRaidDifficulty(bool legacy, int32 forcedDifficulty = -1); void ResetInstances(uint8 method, bool isRaid, bool isLegacy); void SendResetInstanceSuccess(uint32 MapId); @@ -2143,7 +2143,7 @@ class Player : public Unit, public GridObject<Player> bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } void UpdateUnderwaterState(Map* m, float x, float y, float z) override; - void SendMessageToSet(WorldPacket const* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet + void SendMessageToSet(WorldPacket const* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); }// overwrite Object::SendMessageToSet void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) override; // overwrite Object::SendMessageToSetInRange void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool own_team_only); void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) override; @@ -2522,8 +2522,7 @@ class Player : public Unit, public GridObject<Player> uint8 GetSubGroup() const { return m_group.getSubGroup(); } uint32 GetGroupUpdateFlag() const { return m_groupUpdateMask; } void SetGroupUpdateFlag(uint32 flag) { m_groupUpdateMask |= flag; } - uint64 GetAuraUpdateMaskForRaid() const { return m_auraRaidUpdateMask; } - void SetAuraUpdateMaskForRaid(uint8 slot) { m_auraRaidUpdateMask |= (uint64(1) << slot); } + void RemoveGroupUpdateFlag(uint32 flag) { m_groupUpdateMask &= ~flag; } Player* GetNextRandomRaidMember(float radius); PartyResult CanUninviteFromGroup(ObjectGuid guidMember = ObjectGuid::Empty) const; @@ -2761,7 +2760,7 @@ class Player : public Unit, public GridObject<Player> Difficulty m_dungeonDifficulty; Difficulty m_raidDifficulty; Difficulty m_legacyRaidDifficulty; - Difficulty m_raidMapDifficulty; + Difficulty m_prevMapDifficulty; uint32 m_atLoginFlags; @@ -2889,7 +2888,6 @@ class Player : public Unit, public GridObject<Player> GroupReference m_originalGroup; Group* m_groupInvite; uint32 m_groupUpdateMask; - uint64 m_auraRaidUpdateMask; bool m_bPassOnGroupLoot; // last used pet number (for BG's) @@ -2912,7 +2910,7 @@ class Player : public Unit, public GridObject<Player> uint8 m_grantableLevels; - CUFProfile* _CUFProfiles[MAX_CUF_PROFILES]; + std::array<std::unique_ptr<CUFProfile>, MAX_CUF_PROFILES> _CUFProfiles = {}; private: // internal common parts for CanStore/StoreItem functions diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 7034f7fbdc5..f449cec1eef 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -231,7 +231,7 @@ void Transport::Update(uint32 diff) sScriptMgr->OnTransportUpdate(this, diff); } -void Transport::DelayedUpdate(uint32 diff) +void Transport::DelayedUpdate(uint32 /*diff*/) { if (GetKeyFrames().size() <= 1) return; diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index e9af35ff952..526d2b020e1 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -117,7 +117,6 @@ bool Player::UpdateStats(Stats stat) UpdateMaxHealth(); break; case STAT_INTELLECT: - UpdateMaxPower(POWER_MANA); UpdateAllSpellCritChances(); UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently break; @@ -266,17 +265,6 @@ float Player::GetHealthBonusFromStamina() return stamina * ratio; } -float Player::GetManaBonusFromIntellect() -{ - // Taken from PaperDollFrame.lua - 4.3.4.15595 - float intellect = GetStat(STAT_INTELLECT); - - float baseInt = std::min(20.0f, intellect); - float moreInt = intellect - baseInt; - - return baseInt + (moreInt * 15.0f); -} - void Player::UpdateMaxHealth() { UnitMods unitMod = UNIT_MOD_HEALTH; @@ -293,11 +281,9 @@ void Player::UpdateMaxPower(Powers power) { UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - float bonusPower = (power == POWER_MANA && GetCreatePowers(power) > 0) ? GetManaBonusFromIntellect() : 0; - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower; + value += GetModifierValue(unitMod, TOTAL_VALUE); value *= GetModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, uint32(value)); @@ -746,10 +732,6 @@ void Player::UpdateManaRegen() // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen spirit_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA); - // SpiritRegen(SPI, INT, LEVEL) = (0.001 + (SPI x sqrt(INT) x BASE_REGEN[LEVEL])) x 5 - if (GetStat(STAT_INTELLECT) > 0.0f) - spirit_regen *= std::sqrt(GetStat(STAT_INTELLECT)); - // CombatRegen = 5% of Base Mana float base_regen = GetCreateMana() * 0.01f + GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 7ae20779fa7..490c31e683c 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -237,6 +237,7 @@ Unit::Unit(bool isWorldObject) : for (uint8 i = 0; i < UNIT_MOD_END; ++i) { m_auraModifiersGroup[i][BASE_VALUE] = 0.0f; + m_auraModifiersGroup[i][BASE_PCT_EXCLUDE_CREATE] = 100.0f; m_auraModifiersGroup[i][BASE_PCT] = 1.0f; m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; @@ -284,10 +285,6 @@ Unit::Unit(bool isWorldObject) : _oldFactionId = 0; _isWalkingBeforeCharm = false; - - _aiAnimKitId = 0; - _movementAnimKitId = 0; - _meleeAnimKitId = 0; } //////////////////////////////////////////////////////////// @@ -4822,50 +4819,29 @@ void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVict victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount, procAura); } -void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo) +void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* info) { - AuraEffect const* aura = pInfo->auraEff; + AuraEffect const* aura = info->auraEff; + WorldPackets::CombatLog::SpellPeriodicAuraLog data; + data.TargetGUID = GetGUID(); + data.CasterGUID = aura->GetCasterGUID(); + data.SpellID = aura->GetId(); - WorldPacket data(SMSG_SPELL_PERIODIC_AURA_LOG, 30); - data << GetPackGUID(); - data << aura->GetCasterGUID().WriteAsPacked(); - data << uint32(aura->GetId()); // spellId - data << uint32(1); // count - data << uint32(aura->GetAuraType()); // auraId - switch (aura->GetAuraType()) - { - case SPELL_AURA_PERIODIC_DAMAGE: - case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: - data << uint32(pInfo->damage); // damage - data << uint32(pInfo->overDamage); // overkill? - data << uint32(aura->GetSpellInfo()->GetSchoolMask()); - data << uint32(pInfo->absorb); // absorb - data << uint32(pInfo->resist); // resist - data << uint8(pInfo->critical); // new 3.1.2 critical tick - break; - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_OBS_MOD_HEALTH: - data << uint32(pInfo->damage); // damage - data << uint32(pInfo->overDamage); // overheal - data << uint32(pInfo->absorb); // absorb - data << uint8(pInfo->critical); // new 3.1.2 critical tick - break; - case SPELL_AURA_OBS_MOD_POWER: - case SPELL_AURA_PERIODIC_ENERGIZE: - data << uint32(aura->GetMiscValue()); // power type - data << uint32(pInfo->damage); // damage - break; - case SPELL_AURA_PERIODIC_MANA_LEECH: - data << uint32(aura->GetMiscValue()); // power type - data << uint32(pInfo->damage); // amount - data << float(pInfo->multiplier); // gain multiplier - break; - default: - TC_LOG_ERROR("entities.unit", "Unit::SendPeriodicAuraLog: unknown aura %u", uint32(aura->GetAuraType())); - return; - } + /// @todo: should send more logs in one packet when multistrike + WorldPackets::CombatLog::SpellPeriodicAuraLog::SpellLogEffect spellLogEffect; + spellLogEffect.Effect = aura->GetAuraType(); + spellLogEffect.Amount = info->damage; + spellLogEffect.OverHealOrKill = info->overDamage; + spellLogEffect.SchoolMaskOrPower = aura->GetSpellInfo()->GetSchoolMask(); + spellLogEffect.AbsorbedOrAmplitude = info->absorb; + spellLogEffect.Resisted = info->resist; + spellLogEffect.Crit = info->critical; + spellLogEffect.Multistrike = false; // NYI + /// @todo: implement debug info - SendMessageToSet(&data, true); + data.Effects.push_back(spellLogEffect); + + SendMessageToSet(data.Write(), true); } void Unit::SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo) @@ -6957,15 +6933,11 @@ void Unit::setPowerType(Powers new_powertype) if (ToPlayer()->GetGroup()) ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE); } - else if (Pet* pet = ToCreature()->ToPet()) + /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE); - } - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE); + }*/ float powerMultiplier = 1.0f; if (!IsPet()) @@ -11245,6 +11217,7 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f switch (modifierType) { case BASE_VALUE: + case BASE_PCT_EXCLUDE_CREATE: case TOTAL_VALUE: m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; break; @@ -11320,7 +11293,8 @@ float Unit::GetTotalStatValue(Stats stat) const return 0.0f; // value = ((base_value * base_pct) + total_value) * total_pct - float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat); + float value = CalculatePct(m_auraModifiersGroup[unitMod][BASE_VALUE], std::max(m_auraModifiersGroup[unitMod][BASE_PCT_EXCLUDE_CREATE], -100.0f)); + value += GetCreateStat(stat); value *= m_auraModifiersGroup[unitMod][BASE_PCT]; value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; @@ -11339,7 +11313,7 @@ float Unit::GetTotalAuraModValue(UnitMods unitMod) const if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) return 0.0f; - float value = m_auraModifiersGroup[unitMod][BASE_VALUE]; + float value = CalculatePct(m_auraModifiersGroup[unitMod][BASE_VALUE], std::max(m_auraModifiersGroup[unitMod][BASE_PCT_EXCLUDE_CREATE], -100.0f)); value *= m_auraModifiersGroup[unitMod][BASE_PCT]; value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; @@ -11470,11 +11444,7 @@ void Unit::SetHealth(uint32 val) else if (Pet* pet = ToCreature()->ToPet()) { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP); - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP); } } @@ -11495,11 +11465,7 @@ void Unit::SetMaxHealth(uint32 val) else if (Pet* pet = ToCreature()->ToPet()) { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP); - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP); } if (val < health) @@ -11551,15 +11517,11 @@ void Unit::SetPower(Powers power, int32 val) if (player->GetGroup()) player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); } - else if (Pet* pet = ToCreature()->ToPet()) + /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); - } - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); + }*/ } void Unit::SetMaxPower(Powers power, int32 val) @@ -11577,15 +11539,11 @@ void Unit::SetMaxPower(Powers power, int32 val) if (ToPlayer()->GetGroup()) ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); } - else if (Pet* pet = ToCreature()->ToPet()) + /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); - } - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); + }*/ if (val < cur_power) SetPower(power, val); @@ -13007,23 +12965,13 @@ void Unit::UpdateAuraForGroup(uint8 slot) if (Player* player = ToPlayer()) { if (player->GetGroup()) - { player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS); - player->SetAuraUpdateMaskForRaid(slot); - } } else if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsPet()) { Pet* pet = ((Pet*)this); if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - { - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS); - pet->SetAuraUpdateMaskForRaid(slot); - } - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS); } } @@ -13401,45 +13349,6 @@ void Unit::SendDurabilityLoss(Player* receiver, uint32 percent) receiver->GetSession()->SendPacket(packet.Write()); } -void Unit::SetAIAnimKitId(uint16 animKitId) -{ - if (_aiAnimKitId == animKitId) - return; - - _aiAnimKitId = animKitId; - - WorldPacket data(SMSG_SET_AI_ANIM_KIT, 8 + 2); - data << GetPackGUID(); - data << uint16(animKitId); - SendMessageToSet(&data, true); -} - -void Unit::SetMovementAnimKitId(uint16 animKitId) -{ - if (_movementAnimKitId == animKitId) - return; - - _movementAnimKitId = animKitId; - - WorldPacket data(SMSG_SET_MOVEMENT_ANIM_KIT, 8 + 2); - data << GetPackGUID(); - data << uint16(animKitId); - SendMessageToSet(&data, true); -} - -void Unit::SetMeleeAnimKitId(uint16 animKitId) -{ - if (_meleeAnimKitId == animKitId) - return; - - _meleeAnimKitId = animKitId; - - WorldPacket data(SMSG_SET_MELEE_ANIM_KIT, 8 + 2); - data << GetPackGUID(); - data << uint16(animKitId); - SendMessageToSet(&data, true); -} - void Unit::PlayOneShotAnimKit(uint16 animKitId) { WorldPacket data(SMSG_PLAY_ONE_SHOT_ANIM_KIT, 7+2); @@ -16401,7 +16310,7 @@ void Unit::Whisper(std::string const& text, Language language, Player* target, b LocaleConstant locale = target->GetSession()->GetSessionDbLocaleIndex(); WorldPackets::Chat::Chat packet; - packet.Initalize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale); + packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale); target->SendDirectMessage(packet.Write()); } @@ -16448,7 +16357,7 @@ void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/ LocaleConstant locale = target->GetSession()->GetSessionDbLocaleIndex(); WorldPackets::Chat::Chat packet; - packet.Initalize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, getGender()), 0, "", locale); + packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, getGender()), 0, "", locale); target->SendDirectMessage(packet.Write()); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 252f044b4ef..538bcea9eba 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -330,13 +330,6 @@ enum UnitRename #define MAX_AGGRO_RESET_TIME 10 // in seconds #define MAX_AGGRO_RADIUS 45.0f // yards -enum Swing -{ - NOSWING = 0, - SINGLEHANDEDSWING = 1, - TWOHANDEDSWING = 2 -}; - enum VictimState { VICTIMSTATE_INTACT = 0, // set when attacker misses @@ -418,7 +411,7 @@ namespace Movement } typedef std::list<Unit*> UnitList; -typedef std::list< std::pair<Aura*, uint8> > DispelChargesList; +typedef std::list<std::pair<Aura*, uint8>> DispelChargesList; struct SpellImmune { @@ -431,10 +424,11 @@ typedef std::list<SpellImmune> SpellImmuneList; enum UnitModifierType { BASE_VALUE = 0, - BASE_PCT = 1, - TOTAL_VALUE = 2, - TOTAL_PCT = 3, - MODIFIER_TYPE_END = 4 + BASE_PCT_EXCLUDE_CREATE = 1, // percent modifier affecting all stat values from auras and gear but not player base for level + BASE_PCT = 2, + TOTAL_VALUE = 3, + TOTAL_PCT = 4, + MODIFIER_TYPE_END = 5 }; enum WeaponDamageRange @@ -443,13 +437,6 @@ enum WeaponDamageRange MAXDAMAGE }; -enum DamageTypeToSchool -{ - RESISTANCE, - DAMAGE_DEALT, - DAMAGE_TAKEN -}; - enum AuraRemoveMode { AURA_REMOVE_NONE = 0, @@ -1489,12 +1476,6 @@ class Unit : public WorldObject MountCapabilityEntry const* GetMountCapability(uint32 mountType) const; void SendDurabilityLoss(Player* receiver, uint32 percent); - uint16 GetAIAnimKitId() const { return _aiAnimKitId; } - void SetAIAnimKitId(uint16 animKitId); - uint16 GetMovementAnimKitId() const { return _movementAnimKitId; } - void SetMovementAnimKitId(uint16 animKitId); - uint16 GetMeleeAnimKitId() const { return _meleeAnimKitId; } - void SetMeleeAnimKitId(uint16 animKitId); void PlayOneShotAnimKit(uint16 animKitId); uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } @@ -1986,7 +1967,7 @@ class Unit : public WorldObject void TauntApply(Unit* victim); void TauntFadeOut(Unit* taunter); ThreatManager& getThreatManager() { return m_ThreatManager; } - void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); }; + void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); } void removeHatedBy(HostileReference* /*pHostileReference*/) { /* nothing to do yet */ } HostileRefManager& getHostileRefManager() { return m_HostileRefManager; } @@ -2346,10 +2327,6 @@ class Unit : public WorldObject time_t _lastDamagedTime; // Part of Evade mechanics - uint16 _aiAnimKitId; - uint16 _movementAnimKitId; - uint16 _meleeAnimKitId; - SpellHistory* _spellHistory; }; diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index 5edd6f3da2d..6f3b5c63180 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -98,7 +98,7 @@ class GameEventMgr { private: GameEventMgr(); - ~GameEventMgr() { }; + ~GameEventMgr() { } public: static GameEventMgr* instance() diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp index 3087de37472..749ebb562c5 100644 --- a/src/server/game/Garrison/Garrison.cpp +++ b/src/server/game/Garrison/Garrison.cpp @@ -25,7 +25,8 @@ Garrison::Garrison(Player* owner) : _owner(owner), _siteLevel(nullptr), _followe { } -bool Garrison::LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings) +bool Garrison::LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings, + PreparedQueryResult followers, PreparedQueryResult abilities) { if (!garrison) return false; @@ -76,6 +77,59 @@ bool Garrison::LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blue } while (buildings->NextRow()); } + // 0 1 2 3 4 5 6 7 8 9 + // SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ? + if (followers) + { + do + { + Field* fields = followers->Fetch(); + + uint64 dbId = fields[0].GetUInt64(); + uint32 followerId = fields[1].GetUInt32(); + if (!sGarrFollowerStore.LookupEntry(followerId)) + continue; + + _followerIds.insert(followerId); + Follower& follower = _followers[dbId]; + follower.PacketInfo.DbID = dbId; + follower.PacketInfo.GarrFollowerID = followerId; + follower.PacketInfo.Quality = fields[2].GetUInt32(); + follower.PacketInfo.FollowerLevel = fields[3].GetUInt32(); + follower.PacketInfo.ItemLevelWeapon = fields[4].GetUInt32(); + follower.PacketInfo.ItemLevelArmor = fields[5].GetUInt32(); + follower.PacketInfo.Xp = fields[6].GetUInt32(); + follower.PacketInfo.CurrentBuildingID = fields[7].GetUInt32(); + follower.PacketInfo.CurrentMissionID = fields[8].GetUInt32(); + follower.PacketInfo.FollowerStatus = fields[9].GetUInt32(); + if (!sGarrBuildingStore.LookupEntry(follower.PacketInfo.CurrentBuildingID)) + follower.PacketInfo.CurrentBuildingID = 0; + + //if (!sGarrMissionStore.LookupEntry(follower.PacketInfo.CurrentMissionID)) + // follower.PacketInfo.CurrentMissionID = 0; + + } while (followers->NextRow()); + + if (abilities) + { + do + { + Field* fields = abilities->Fetch(); + uint64 dbId = fields[0].GetUInt64(); + GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(fields[1].GetUInt32()); + + if (!ability) + continue; + + auto itr = _followers.find(dbId); + if (itr == _followers.end()) + continue; + + itr->second.PacketInfo.AbilityID.push_back(ability); + } while (abilities->NextRow()); + } + } + return true; } @@ -93,6 +147,10 @@ void Garrison::SaveToDB(SQLTransaction& trans) stmt->setUInt64(0, _owner->GetGUID().GetCounter()); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON); stmt->setUInt64(0, _owner->GetGUID().GetCounter()); stmt->setUInt32(1, _siteLevel->ID); @@ -121,6 +179,35 @@ void Garrison::SaveToDB(SQLTransaction& trans) trans->Append(stmt); } } + + for (auto const& p : _followers) + { + Follower const& follower = p.second; + uint8 index = 0; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS); + stmt->setUInt64(index++, follower.PacketInfo.DbID); + stmt->setUInt64(index++, _owner->GetGUID().GetCounter()); + stmt->setUInt32(index++, follower.PacketInfo.GarrFollowerID); + stmt->setUInt32(index++, follower.PacketInfo.Quality); + stmt->setUInt32(index++, follower.PacketInfo.FollowerLevel); + stmt->setUInt32(index++, follower.PacketInfo.ItemLevelWeapon); + stmt->setUInt32(index++, follower.PacketInfo.ItemLevelArmor); + stmt->setUInt32(index++, follower.PacketInfo.Xp); + stmt->setUInt32(index++, follower.PacketInfo.CurrentBuildingID); + stmt->setUInt32(index++, follower.PacketInfo.CurrentMissionID); + stmt->setUInt32(index++, follower.PacketInfo.FollowerStatus); + trans->Append(stmt); + + uint8 slot = 0; + for (GarrAbilityEntry const* ability : follower.PacketInfo.AbilityID) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES); + stmt->setUInt64(0, follower.PacketInfo.DbID); + stmt->setUInt32(1, ability->ID); + stmt->setUInt8(2, slot++); + trans->Append(stmt); + } + } } bool Garrison::Create(uint32 garrSiteId) @@ -348,15 +435,17 @@ void Garrison::AddFollower(uint32 garrFollowerId) { WorldPackets::Garrison::GarrisonAddFollowerResult addFollowerResult; GarrFollowerEntry const* followerEntry = sGarrFollowerStore.LookupEntry(garrFollowerId); - if (_followers.count(garrFollowerId) || !followerEntry) + if (_followerIds.count(garrFollowerId) || !followerEntry) { addFollowerResult.Result = GARRISON_GENERIC_UNKNOWN_ERROR; _owner->SendDirectMessage(addFollowerResult.Write()); return; } - Follower& follower = _followers[garrFollowerId]; - follower.PacketInfo.DbID = sGarrisonMgr.GenerateFollowerDbId(); + _followerIds.insert(garrFollowerId); + uint64 dbId = sGarrisonMgr.GenerateFollowerDbId(); + Follower& follower = _followers[dbId]; + follower.PacketInfo.DbID = dbId; follower.PacketInfo.GarrFollowerID = garrFollowerId; follower.PacketInfo.Quality = followerEntry->Quality; // TODO: handle magic upgrades follower.PacketInfo.FollowerLevel = followerEntry->Level; @@ -370,6 +459,17 @@ void Garrison::AddFollower(uint32 garrFollowerId) addFollowerResult.Follower = follower.PacketInfo; _owner->SendDirectMessage(addFollowerResult.Write()); + + _owner->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER, follower.PacketInfo.DbID); +} + +Garrison::Follower const* Garrison::GetFollower(uint64 dbId) const +{ + auto itr = _followers.find(dbId); + if (itr != _followers.end()) + return &itr->second; + + return nullptr; } void Garrison::SendInfo() @@ -481,7 +581,7 @@ GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 if (!_owner->HasCurrency(building->CostCurrencyID, building->CostCurrencyAmount)) return GARRISON_ERROR_NOT_ENOUGH_CURRENCY; - if (!_owner->HasEnoughMoney(uint64(building->CostMoney * GOLD))) + if (!_owner->HasEnoughMoney(uint64(building->CostMoney) * GOLD)) return GARRISON_ERROR_NOT_ENOUGH_GOLD; // New building cannot replace another building currently under construction @@ -583,3 +683,8 @@ bool Garrison::Building::CanActivate() const return false; } + +uint32 Garrison::Follower::GetItemLevel() const +{ + return (PacketInfo.ItemLevelWeapon + PacketInfo.ItemLevelArmor) / 2; +} diff --git a/src/server/game/Garrison/Garrison.h b/src/server/game/Garrison/Garrison.h index 348998b276c..71d67a1b6b5 100644 --- a/src/server/game/Garrison/Garrison.h +++ b/src/server/game/Garrison/Garrison.h @@ -43,7 +43,8 @@ enum GarrisonAbilityFlags GARRISON_ABILITY_CANNOT_ROLL = 0x02, GARRISON_ABILITY_HORDE_ONLY = 0x04, GARRISON_ABILITY_ALLIANCE_ONLY = 0x08, - GARRISON_ABILITY_FLAG_CANNOT_REMOVE = 0x10 + GARRISON_ABILITY_FLAG_CANNOT_REMOVE = 0x10, + GARRISON_ABILITY_FLAG_EXCLUSIVE = 0x20 }; enum GarrisonError @@ -99,12 +100,15 @@ public: struct Follower { + uint32 GetItemLevel() const; + WorldPackets::Garrison::GarrisonFollower PacketInfo; }; explicit Garrison(Player* owner); - bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings); + bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings, + PreparedQueryResult followers, PreparedQueryResult abilities); void SaveToDB(SQLTransaction& trans); bool Create(uint32 garrSiteId); @@ -128,6 +132,7 @@ public: // Followers void AddFollower(uint32 garrFollowerId); + Follower const* GetFollower(uint64 dbId) const; void SendInfo(); void SendRemoteInfo() const; @@ -148,6 +153,7 @@ private: std::unordered_map<uint32 /*garrPlotInstanceId*/, Plot> _plots; std::unordered_set<uint32 /*garrBuildingId*/> _knownBuildings; std::unordered_map<uint64 /*dbId*/, Follower> _followers; + std::unordered_set<uint32> _followerIds; }; #endif // Garrison_h__ diff --git a/src/server/game/Garrison/GarrisonMap.cpp b/src/server/game/Garrison/GarrisonMap.cpp index 7316504d185..b9cf63140b4 100644 --- a/src/server/game/Garrison/GarrisonMap.cpp +++ b/src/server/game/Garrison/GarrisonMap.cpp @@ -97,7 +97,7 @@ void GarrisonGridLoader::Visit(CreatureMapType& /*m*/) } GarrisonMap::GarrisonMap(uint32 id, time_t expiry, uint32 instanceId, Map* parent, ObjectGuid const& owner) - : Map(id, expiry, instanceId, DIFFICULTY_NORMAL, parent), _owner(owner) + : Map(id, expiry, instanceId, DIFFICULTY_NORMAL, parent), _owner(owner), _loadingPlayer(nullptr) { GarrisonMap::InitVisibilityDistance(); } @@ -112,6 +112,9 @@ void GarrisonMap::LoadGridObjects(NGridType* grid, Cell const& cell) Garrison* GarrisonMap::GetGarrison() { + if (_loadingPlayer) + return _loadingPlayer->GetGarrison(); + if (Player* owner = ObjectAccessor::FindConnectedPlayer(_owner)) return owner->GetGarrison(); @@ -124,3 +127,16 @@ void GarrisonMap::InitVisibilityDistance() m_VisibleDistance = World::GetMaxVisibleDistanceInBGArenas(); m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInBGArenas(); } + +bool GarrisonMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/) +{ + if (player->GetGUID() == _owner) + _loadingPlayer = player; + + bool result = Map::AddPlayerToMap(player, initPlayer); + + if (player->GetGUID() == _owner) + _loadingPlayer = nullptr; + + return result; +} diff --git a/src/server/game/Garrison/GarrisonMap.h b/src/server/game/Garrison/GarrisonMap.h index 0ccc77b05fa..5f5c9b134b7 100644 --- a/src/server/game/Garrison/GarrisonMap.h +++ b/src/server/game/Garrison/GarrisonMap.h @@ -21,6 +21,7 @@ #include "Map.h" class Garrison; +class Player; class GarrisonMap : public Map { @@ -32,8 +33,11 @@ public: void InitVisibilityDistance() override; + bool AddPlayerToMap(Player* player, bool initPlayer = true) override; + private: ObjectGuid _owner; + Player* _loadingPlayer; ///< @workaround Player is not registered in ObjectAccessor during login }; #endif // GarrisonMap_h__ diff --git a/src/server/game/Garrison/GarrisonMgr.cpp b/src/server/game/Garrison/GarrisonMgr.cpp index 3229ee7d02a..f95acef952c 100644 --- a/src/server/game/Garrison/GarrisonMgr.cpp +++ b/src/server/game/Garrison/GarrisonMgr.cpp @@ -17,6 +17,7 @@ #include "GarrisonMgr.h" #include "Containers.h" +#include "DatabaseEnv.h" #include "Garrison.h" #include "ObjectDefines.h" #include "World.h" @@ -55,6 +56,9 @@ void GarrisonMgr::Initialize() } } } + + InitializeDbIdSequences(); + LoadFollowerClassSpecAbilities(); } GarrSiteLevelEntry const* GarrisonMgr::GetGarrSiteLevelEntry(uint32 garrSiteId, uint32 level) const @@ -139,11 +143,12 @@ uint32 const AbilitiesForQuality[][2] = { 2, 3 } // Legendary }; -std::list<uint32> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const +std::list<GarrAbilityEntry const*> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const { ASSERT(faction < 2); - std::list<uint32> result; + bool hasForcedExclusiveTrait = false; + std::list<GarrAbilityEntry const*> result; int32 slots[2] = { AbilitiesForQuality[quality][0], AbilitiesForQuality[quality][1] }; GarrAbilities const* abilities = nullptr; @@ -151,7 +156,7 @@ std::list<uint32> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* fo if (itr != _garrisonFollowerAbilities[faction].end()) abilities = &itr->second; - std::list<uint32> abilityList, forcedAbilities, traitList, forcedTraits; + std::list<GarrAbilityEntry const*> abilityList, forcedAbilities, traitList, forcedTraits; if (abilities) { for (GarrAbilityEntry const* ability : abilities->Counters) @@ -162,9 +167,9 @@ std::list<uint32> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* fo continue; if (ability->Flags & GARRISON_ABILITY_FLAG_CANNOT_REMOVE) - forcedAbilities.push_back(ability->ID); + forcedAbilities.push_back(ability); else - abilityList.push_back(ability->ID); + abilityList.push_back(ability); } for (GarrAbilityEntry const* ability : abilities->Traits) @@ -175,36 +180,51 @@ std::list<uint32> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* fo continue; if (ability->Flags & GARRISON_ABILITY_FLAG_CANNOT_REMOVE) - forcedTraits.push_back(ability->ID); + forcedTraits.push_back(ability); else - traitList.push_back(ability->ID); + traitList.push_back(ability); } } Trinity::Containers::RandomResizeList(abilityList, std::max<int32>(0, slots[0] - forcedAbilities.size())); Trinity::Containers::RandomResizeList(traitList, std::max<int32>(0, slots[1] - forcedTraits.size())); - // Add counters specified in GarrFollowerXAbility.db2 before generic classspec ones on follower creation + // Add abilities specified in GarrFollowerXAbility.db2 before generic classspec ones on follower creation if (initial) { forcedAbilities.splice(forcedAbilities.end(), abilityList); forcedTraits.splice(forcedTraits.end(), traitList); } - if (slots[0] > forcedAbilities.size() + abilityList.size()) + forcedAbilities.sort(); + abilityList.sort(); + forcedTraits.sort(); + traitList.sort(); + + // check if we have a trait from exclusive category + for (GarrAbilityEntry const* ability : forcedTraits) { - std::list<uint32> classSpecAbilities; // = GetDefaultClassSpecAbilities(follower, faction) + if (ability->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE) + { + hasForcedExclusiveTrait = true; + break; + } + } - abilityList.splice(abilityList.end(), classSpecAbilities); - abilityList.sort(); - abilityList.unique(); + if (slots[0] > forcedAbilities.size() + abilityList.size()) + { + std::list<GarrAbilityEntry const*> classSpecAbilities = GetClassSpecAbilities(follower, faction); + std::list<GarrAbilityEntry const*> classSpecAbilitiesTemp, classSpecAbilitiesTemp2; + classSpecAbilitiesTemp2.swap(abilityList); + std::set_difference(classSpecAbilities.begin(), classSpecAbilities.end(), forcedAbilities.begin(), forcedAbilities.end(), std::back_inserter(classSpecAbilitiesTemp)); + std::set_union(classSpecAbilitiesTemp.begin(), classSpecAbilitiesTemp.end(), classSpecAbilitiesTemp2.begin(), classSpecAbilitiesTemp2.end(), std::back_inserter(abilityList)); Trinity::Containers::RandomResizeList(abilityList, std::max<int32>(0, slots[0] - forcedAbilities.size())); } if (slots[1] > forcedTraits.size() + traitList.size()) { - std::list<uint32> genericTraits; + std::list<GarrAbilityEntry const*> genericTraits, genericTraitsTemp; for (GarrAbilityEntry const* ability : _garrisonFollowerRandomTraits) { if (ability->Flags & GARRISON_ABILITY_HORDE_ONLY && faction != GARRISON_FACTION_INDEX_HORDE) @@ -212,14 +232,44 @@ std::list<uint32> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* fo else if (ability->Flags & GARRISON_ABILITY_ALLIANCE_ONLY && faction != GARRISON_FACTION_INDEX_ALLIANCE) continue; - genericTraits.push_back(ability->ID); + // forced exclusive trait exists, skip other ones entirely + if (hasForcedExclusiveTrait && ability->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE) + continue; + + genericTraitsTemp.push_back(ability); } - traitList.splice(traitList.end(), genericTraits); - traitList.sort(); - traitList.unique(); + std::set_difference(genericTraitsTemp.begin(), genericTraitsTemp.end(), forcedTraits.begin(), forcedTraits.end(), std::back_inserter(genericTraits)); + genericTraits.splice(genericTraits.begin(), traitList); + // "split" the list into two parts [nonexclusive, exclusive] to make selection later easier + genericTraits.sort([](GarrAbilityEntry const* a1, GarrAbilityEntry const* a2) + { + uint32 e1 = a1->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE; + uint32 e2 = a2->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE; + if (e1 != e2) + return e1 < e2; + + return a1->ID < a2->ID; + }); + genericTraits.unique(); - Trinity::Containers::RandomResizeList(traitList, std::max<int32>(0, slots[1] - forcedTraits.size())); + std::size_t firstExclusive = 0, total = genericTraits.size(); + for (auto itr = genericTraits.begin(); itr != genericTraits.end(); ++itr, ++firstExclusive) + if ((*itr)->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE) + break; + + while (traitList.size() < std::max<int32>(0, slots[1] - forcedTraits.size()) && total) + { + auto itr = genericTraits.begin(); + std::advance(itr, urand(0, total-- - 1)); + if ((*itr)->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE) + total = firstExclusive; // selected exclusive trait - no other can be selected now + else + --firstExclusive; + + traitList.push_back(*itr); + genericTraits.erase(itr); + } } result.splice(result.end(), forcedAbilities); @@ -229,3 +279,75 @@ std::list<uint32> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* fo return result; } + +std::list<GarrAbilityEntry const*> GarrisonMgr::GetClassSpecAbilities(GarrFollowerEntry const* follower, uint32 faction) const +{ + std::list<GarrAbilityEntry const*> abilities; + uint32 classSpecId; + switch (faction) + { + case GARRISON_FACTION_INDEX_HORDE: + classSpecId = follower->HordeGarrClassSpecID; + break; + case GARRISON_FACTION_INDEX_ALLIANCE: + classSpecId = follower->AllianceGarrClassSpecID; + break; + default: + return abilities; + } + + if (!sGarrClassSpecStore.LookupEntry(classSpecId)) + return abilities; + + auto itr = _garrisonFollowerClassSpecAbilities.find(classSpecId); + if (itr != _garrisonFollowerClassSpecAbilities.end()) + abilities = itr->second; + + return abilities; +} + +void GarrisonMgr::InitializeDbIdSequences() +{ + if (QueryResult result = CharacterDatabase.Query("SELECT MAX(dbId) FROM character_garrison_followers")) + _followerDbIdGenerator = (*result)[0].GetUInt64() + 1; +} + +void GarrisonMgr::LoadFollowerClassSpecAbilities() +{ + QueryResult result = WorldDatabase.Query("SELECT classSpecId, abilityId FROM garrison_follower_class_spec_abilities"); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 garrison follower class spec abilities. DB table `garrison_follower_class_spec_abilities` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + uint32 classSpecId = fields[0].GetUInt32(); + uint32 abilityId = fields[1].GetUInt32(); + + if (!sGarrClassSpecStore.LookupEntry(classSpecId)) + { + TC_LOG_ERROR("sql.sql", "Non-existing GarrClassSpec.db2 entry %u was referenced in `garrison_follower_class_spec_abilities` by row (%u, %u).", classSpecId, classSpecId, abilityId); + continue; + } + + GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(abilityId); + if (!ability) + { + TC_LOG_ERROR("sql.sql", "Non-existing GarrAbility.db2 entry %u was referenced in `garrison_follower_class_spec_abilities` by row (%u, %u).", abilityId, classSpecId, abilityId); + continue; + } + + _garrisonFollowerClassSpecAbilities[classSpecId].push_back(ability); + ++count; + + } while (result->NextRow()); + + for (auto& pair : _garrisonFollowerClassSpecAbilities) + pair.second.sort(); + + TC_LOG_INFO("server.loading", ">> Loaded %u garrison follower class spec abilities.", count); +} diff --git a/src/server/game/Garrison/GarrisonMgr.h b/src/server/game/Garrison/GarrisonMgr.h index f037c0867a0..63810e3c3ab 100644 --- a/src/server/game/Garrison/GarrisonMgr.h +++ b/src/server/game/Garrison/GarrisonMgr.h @@ -45,18 +45,23 @@ public: uint32 GetGarrBuildingPlotInst(uint32 garrBuildingId, uint32 garrSiteLevelPlotInstId) const; GarrBuildingEntry const* GetPreviousLevelBuilding(uint32 buildingType, uint32 currentLevel) const; uint64 GenerateFollowerDbId(); - std::list<uint32> RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const; + std::list<GarrAbilityEntry const*> RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const; + std::list<GarrAbilityEntry const*> GetClassSpecAbilities(GarrFollowerEntry const* follower, uint32 faction) const; private: + void InitializeDbIdSequences(); + void LoadFollowerClassSpecAbilities(); + std::unordered_map<uint32 /*garrSiteId*/, std::vector<GarrSiteLevelPlotInstEntry const*>> _garrisonPlotInstBySiteLevel; std::unordered_map<uint32 /*mapId*/, std::unordered_map<uint32 /*garrPlotId*/, GameObjectsEntry const*>> _garrisonPlots; std::unordered_map<uint32 /*garrPlotId*/, std::unordered_set<uint32/*garrBuildingId*/>> _garrisonBuildingsByPlot; std::unordered_map<uint64 /*garrBuildingId | garrSiteLevelPlotInstId << 32*/, uint32 /*garrBuildingPlotInstId*/> _garrisonBuildingPlotInstances; std::unordered_map<uint32 /*buildingType*/, std::vector<GarrBuildingEntry const*>> _garrisonBuildingsByType; std::unordered_map<uint32 /*garrFollowerId*/, GarrAbilities> _garrisonFollowerAbilities[2]; - std::unordered_set<GarrAbilityEntry const*> _garrisonFollowerRandomTraits; + std::unordered_map<uint32 /*classSpecId*/, std::list<GarrAbilityEntry const*>> _garrisonFollowerClassSpecAbilities; + std::set<GarrAbilityEntry const*> _garrisonFollowerRandomTraits; - uint64 _followerDbIdGenerator; + uint64 _followerDbIdGenerator = UI64LIT(1); }; #define sGarrisonMgr GarrisonMgr::Instance() diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index ac87f58af5c..cdd550a98f2 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -2242,6 +2242,25 @@ bool ObjectMgr::GetPlayerNameByGUID(ObjectGuid const& guid, std::string& name) return false; } +bool ObjectMgr::GetPlayerNameAndClassByGUID(ObjectGuid const& guid, std::string& name, uint8& _class) +{ + if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) + { + name = player->GetName(); + _class = player->getClass(); + return true; + } + + if (CharacterInfo const* characterInfo = sWorld->GetCharacterInfo(guid)) + { + name = characterInfo->Name; + _class = characterInfo->Class; + return true; + } + + return false; +} + uint32 ObjectMgr::GetPlayerTeamByGUID(ObjectGuid const& guid) { if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) @@ -3620,10 +3639,10 @@ void ObjectMgr::LoadQuests() mExclusiveQuestGroups.clear(); QueryResult result = WorldDatabase.Query("SELECT " - //0 1 2 3 4 5 6 7 8 9 10 11 12 - "ID, QuestType, QuestLevel, QuestPackageID, MinLevel, QuestSortID, QuestInfoID, SuggestedGroupNum, RewardNextQuest, RewardXPDifficulty, Float10, RewardMoney, RewardMoneyDifficulty, " - //13 14 15 16 17 18 19 20 21 - "Float13, RewardBonusMoney, RewardDisplaySpell, RewardSpell, RewardHonor, RewardKillHonor, StartItem, Flags, FlagsEx, " + //0 1 2 3 4 5 6 7 8 9 10 + "ID, QuestType, QuestLevel, QuestPackageID, MinLevel, QuestSortID, QuestInfoID, SuggestedGroupNum, RewardNextQuest, RewardXPDifficulty, RewardXPMultiplier, " + //11 12 13 14 15 16 17 18 19 20 21 + "RewardMoney, RewardMoneyDifficulty, Float13, RewardBonusMoney, RewardDisplaySpell, RewardSpell, RewardHonor, RewardKillHonor, StartItem, Flags, FlagsEx, " //22 23 24 25 26 27 28 29 "RewardItem1, RewardAmount1, ItemDrop1, ItemDropQuantity1, RewardItem2, RewardAmount2, ItemDrop2, ItemDropQuantity2, " //30 31 32 33 34 35 36 37 diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index dc26e30773c..4277ab74048 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -780,6 +780,7 @@ class ObjectMgr * @return true if player was found, false otherwise */ static bool GetPlayerNameByGUID(ObjectGuid const& guid, std::string& name); + static bool GetPlayerNameAndClassByGUID(ObjectGuid const& guid, std::string& name, uint8& _class); static uint32 GetPlayerTeamByGUID(ObjectGuid const& guid); static uint32 GetPlayerAccountIdByGUID(ObjectGuid const& guid); static uint32 GetPlayerAccountIdByPlayerName(std::string const& name); @@ -1364,7 +1365,7 @@ class ObjectMgr { auto itr = _guidGenerators.find(high); if (itr == _guidGenerators.end()) - itr = _guidGenerators.insert(std::make_pair(high, std::unique_ptr<ObjectGuidGenerator<high>>(new ObjectGuidGenerator<high>()))).first; + itr = _guidGenerators.insert(std::make_pair(high, Trinity::make_unique<ObjectGuidGenerator<high>>())).first; return *itr->second; } diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index f359e1eff57..fadf7e1970e 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -21,6 +21,7 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "Player.h" +#include "Pet.h" #include "World.h" #include "ObjectMgr.h" #include "GroupMgr.h" @@ -35,6 +36,7 @@ #include "Util.h" #include "LFGMgr.h" #include "UpdateFieldFlags.h" +#include "PartyPackets.h" Roll::Roll(ObjectGuid _guid, LootItem const& li) : itemGUID(_guid), itemid(li.itemid), itemRandomPropId(li.randomPropertyId), itemRandomSuffix(li.randomSuffix), itemCount(li.count), @@ -55,11 +57,15 @@ Loot* Roll::getLoot() Group::Group() : m_leaderGuid(), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL), m_dungeonDifficulty(DIFFICULTY_NORMAL), m_raidDifficulty(DIFFICULTY_NORMAL_RAID), m_legacyRaidDifficulty(DIFFICULTY_10_N), -m_bgGroup(NULL), m_bfGroup(NULL), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(), -m_masterLooterGuid(), m_subGroupsCounts(NULL), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0) +m_bgGroup(nullptr), m_bfGroup(nullptr), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(), +m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0), +m_readyCheckStarted(false), m_readyCheckTimer(0), m_activeMarkers(0) { - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].Clear(); + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; ++i) + m_markers[i] = nullptr; } Group::~Group() @@ -176,7 +182,7 @@ void Group::LoadGroupFromDB(Field* fields) m_looterGuid = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt64()); m_lootThreshold = ItemQualities(fields[3].GetUInt8()); - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].SetRawValue(fields[4 + i].GetBinary()); m_groupType = GroupType(fields[12].GetUInt8()); @@ -199,7 +205,7 @@ void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uin member.guid = ObjectGuid::Create<HighGuid::Player>(guidLow); // skip non-existed member - if (!ObjectMgr::GetPlayerNameByGUID(member.guid, member.name)) + if (!ObjectMgr::GetPlayerNameAndClassByGUID(member.guid, member.name, member._class)) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); stmt->setUInt64(0, guidLow); @@ -207,9 +213,10 @@ void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uin return; } - member.group = subgroup; - member.flags = memberFlags; - member.roles = roles; + member.group = subgroup; + member.flags = memberFlags; + member.roles = roles; + member.readyChecked = false; m_memberSlots.push_back(member); @@ -368,7 +375,7 @@ bool Group::AddMember(Player* player) bool groupFound = false; for (; subGroup < MAX_RAID_SUBGROUPS; ++subGroup) { - if (m_subGroupsCounts[subGroup] < MAXGROUPSIZE) + if (m_subGroupsCounts[subGroup] < MAX_GROUP_SIZE) { groupFound = true; break; @@ -380,11 +387,13 @@ bool Group::AddMember(Player* player) } MemberSlot member; - member.guid = player->GetGUID(); - member.name = player->GetName(); - member.group = subGroup; - member.flags = 0; - member.roles = 0; + member.guid = player->GetGUID(); + member.name = player->GetName(); + member._class = player->getClass(); + member.group = subGroup; + member.flags = 0; + member.roles = 0; + member.readyChecked = false; m_memberSlots.push_back(member); SubGroupCounterIncrease(subGroup); @@ -407,7 +416,7 @@ bool Group::AddMember(Player* player) if (!isRaidGroup()) // reset targetIcons for non-raid-groups { - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].Clear(); } @@ -455,7 +464,11 @@ bool Group::AddMember(Player* player) } } } + player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); + if (Pet* pet = player->GetPet()) + pet->SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); + UpdatePlayerOutOfRange(player); // quest related GO state dependent from raid membership @@ -552,12 +565,6 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R player->GetSession()->SendPacket(&data); } - // Do we really need to send this opcode? - data.Initialize(SMSG_PARTY_UPDATE, 1+1+1+1+8+4+4+8); - data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0); - data << m_guid << uint32(m_counter) << uint32(0) << uint64(0); - player->GetSession()->SendPacket(&data); - _homebindIfInstance(player); } @@ -644,7 +651,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R } } -void Group::ChangeLeader(ObjectGuid newLeaderGuid) +void Group::ChangeLeader(ObjectGuid newLeaderGuid, int8 partyIndex) { member_witerator slot = _getMemberWSlot(newLeaderGuid); @@ -707,9 +714,10 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid) m_leaderName = newLeader->GetName(); ToggleGroupMemberFlag(slot, MEMBER_FLAG_ASSISTANT, false); - WorldPacket data(SMSG_GROUP_NEW_LEADER, m_leaderName.size()+1); - data << slot->name; - BroadcastPacket(&data, true); + WorldPackets::Party::GroupNewLeader groupNewLeader; + groupNewLeader.Name = m_leaderName; + groupNewLeader.PartyIndex = partyIndex; + BroadcastPacket(groupNewLeader.Write(), true); } void Group::Disband(bool hideDestroy /* = false */) @@ -1491,45 +1499,38 @@ void Group::CountTheRoll(Rolls::iterator rollI) delete roll; } -void Group::SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid) +void Group::SetTargetIcon(uint8 symbol, ObjectGuid target, ObjectGuid changedBy, uint8 partyIndex) { - if (id >= TARGETICONCOUNT) + if (symbol >= TARGET_ICONS_COUNT) return; // clean other icons - if (!targetGuid.IsEmpty()) - for (int i = 0; i < TARGETICONCOUNT; ++i) - if (m_targetIcons[i] == targetGuid) - SetTargetIcon(i, ObjectGuid::Empty, ObjectGuid::Empty); + if (!target.IsEmpty()) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) + if (m_targetIcons[i] == target) + SetTargetIcon(i, ObjectGuid::Empty, changedBy, partyIndex); - m_targetIcons[id] = targetGuid; + m_targetIcons[symbol] = target; - WorldPacket data(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, (1+8+1+8)); - data << uint8(0); // set targets - data << whoGuid; - data << uint8(id); - data << targetGuid; - BroadcastPacket(&data, true); + WorldPackets::Party::SendRaidTargetUpdateSingle updateSingle; + updateSingle.PartyIndex = partyIndex; + updateSingle.Target = target; + updateSingle.ChangedBy = changedBy; + updateSingle.Symbol = symbol; + BroadcastPacket(updateSingle.Write(), true); } -void Group::SendTargetIconList(WorldSession* session) +void Group::SendTargetIconList(WorldSession* session, int8 partyIndex) { if (!session) return; - WorldPacket data(SMSG_SEND_RAID_TARGET_UPDATE_ALL, (1+TARGETICONCOUNT*9)); - data << uint8(1); // list targets + WorldPackets::Party::SendRaidTargetUpdateAll updateAll; + updateAll.PartyIndex = partyIndex; + for (uint8 i = 0; i < TARGET_ICONS_COUNT; i++) + updateAll.TargetIcons.insert(std::pair<uint8, ObjectGuid>(i, m_targetIcons[i])); - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) - { - if (m_targetIcons[i].IsEmpty()) - continue; - - data << uint8(i); - data << m_targetIcons[i]; - } - - session->SendPacket(&data); + session->SendPacket(updateAll.Write()); } void Group::SendUpdate() @@ -1556,56 +1557,79 @@ void Group::SendUpdateToPlayer(ObjectGuid playerGUID, MemberSlot* slot) slot = &(*witr); } - WorldPacket data(SMSG_PARTY_UPDATE, (1+1+1+1+1+4+8+4+4+(GetMembersCount()-1)*(13+8+1+1+1+1)+8+1+8+1+1+1+1)); - data << uint8(m_groupType); // group type (flags in 3.3) - data << uint8(slot->group); - data << uint8(slot->flags); - data << uint8(slot->roles); - if (isLFGGroup()) - { - 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 - } + WorldPackets::Party::PartyUpdate partyUpdate; - data << m_guid; - data << uint32(m_counter++); // 3.3, value increases every time this packet gets sent - data << uint32(GetMembersCount()-1); - for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) + partyUpdate.PartyType = m_groupType; + partyUpdate.PartyIndex = 0; + partyUpdate.PartyFlags = uint8(IsCreated()); + + partyUpdate.PartyGUID = m_guid; + partyUpdate.LeaderGUID = m_leaderGuid; + + partyUpdate.SequenceNum = m_counter++; // 3.3, value increases every time this packet gets sent + + partyUpdate.MyIndex = -1; + uint8 index = 0; + for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr, ++index) { if (slot->guid == citr->guid) - continue; + partyUpdate.MyIndex = index; Player* member = ObjectAccessor::FindConnectedPlayer(citr->guid); - uint8 onlineState = (member && !member->GetSession()->PlayerLogout()) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE; - onlineState = onlineState | ((isBGGroup() || isBFGroup()) ? MEMBER_STATUS_PVP : 0); + WorldPackets::Party::GroupPlayerInfos playerInfos; - data << citr->name; - data << citr->guid; // guid - data << uint8(onlineState); // online-state - data << uint8(citr->group); // groupid - data << uint8(citr->flags); // See enum GroupMemberFlags - data << uint8(citr->roles); // Lfg Roles + playerInfos.GUID = citr->guid; + playerInfos.Name = citr->name; + playerInfos.Class = citr->_class; + + playerInfos.Status = MEMBER_STATUS_OFFLINE; + if (member && member->GetSession() && !member->GetSession()->PlayerLogout()) + playerInfos.Status = MEMBER_STATUS_ONLINE | (isBGGroup() || isBFGroup() ? MEMBER_STATUS_PVP : 0); + + playerInfos.Subgroup = citr->group; // groupid + playerInfos.Flags = citr->flags; // See enum GroupMemberFlags + playerInfos.RolesAssigned = citr->roles; // Lfg Roles + + partyUpdate.PlayerList.push_back(playerInfos); } - data << m_leaderGuid; // leader guid + if (GetMembersCount() > 1) + { + // LootSettings + partyUpdate.LootSettings = boost::in_place(); + partyUpdate.LootSettings->Method = m_lootMethod; + partyUpdate.LootSettings->Threshold = m_lootThreshold; + partyUpdate.LootSettings->LootMaster = m_lootMethod == MASTER_LOOT ? m_masterLooterGuid : ObjectGuid::Empty; + + // Difficulty Settings + partyUpdate.DifficultySettings = boost::in_place(); + partyUpdate.DifficultySettings->DungeonDifficultyID = m_dungeonDifficulty; + partyUpdate.DifficultySettings->RaidDifficultyID = m_raidDifficulty; + partyUpdate.DifficultySettings->LegacyRaidDifficultyID = m_legacyRaidDifficulty; + } - if (GetMembersCount() - 1) + // LfgInfos + if (isLFGGroup()) { - data << uint8(m_lootMethod); // loot method + partyUpdate.LfgInfos = boost::in_place(); - if (m_lootMethod == MASTER_LOOT) - data << m_masterLooterGuid; // master looter guid - else - data << uint64(0); + partyUpdate.LfgInfos->Slot = sLFGMgr->GetDungeon(m_guid); + partyUpdate.LfgInfos->BootCount = 0; // new 6.x + partyUpdate.LfgInfos->Aborted = false; // new 6.x + + partyUpdate.LfgInfos->MyFlags = 0; // new 6.x + partyUpdate.LfgInfos->MyRandomSlot = 0; // new 6.x + + partyUpdate.LfgInfos->MyPartialClear = sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0; // FIXME - Dungeon save status? 2 = done + partyUpdate.LfgInfos->MyGearDiff = 0.f; // new 6.x + partyUpdate.LfgInfos->MyFirstReward = false; // new 6.x - data << uint8(m_lootThreshold); // loot threshold - data << uint8(m_dungeonDifficulty); // Dungeon Difficulty - data << uint8(m_raidDifficulty); // Raid Difficulty + partyUpdate.LfgInfos->MyStrangerCount = 0; // new 6.x + partyUpdate.LfgInfos->MyKickVoteCount = 0; // new 6.x } - player->GetSession()->SendPacket(&data); + player->GetSession()->SendPacket(partyUpdate.Write()); } void Group::UpdatePlayerOutOfRange(Player* player) @@ -1613,15 +1637,15 @@ void Group::UpdatePlayerOutOfRange(Player* player) if (!player || !player->IsInWorld()) return; - WorldPacket data; - player->GetSession()->BuildPartyMemberStatsChangedPacket(player, &data); + WorldPackets::Party::PartyMemberStats packet; + packet.Initialize(player); Player* member; for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { member = itr->GetSource(); if (member && member != player && (!member->IsInMap(player) || !member->IsWithinDist(player, member->GetSightRange(), false))) - member->GetSession()->SendPacket(&data); + member->GetSession()->SendPacket(packet.Write()); } } @@ -1653,32 +1677,6 @@ void Group::BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRai } } -void Group::BroadcastReadyCheck(WorldPacket const* packet) -{ - for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* player = itr->GetSource(); - if (player && player->GetSession()) - if (IsLeader(player->GetGUID()) || IsAssistant(player->GetGUID())) - player->GetSession()->SendPacket(packet); - } -} - -void Group::OfflineReadyCheck() -{ - for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) - { - Player* player = ObjectAccessor::FindConnectedPlayer(citr->guid); - if (!player || !player->GetSession()) - { - WorldPacket data(SMSG_READY_CHECK_RESPONSE, 9); - data << citr->guid; - data << uint8(0); - BroadcastReadyCheck(&data); - } - } -} - bool Group::_setMembersGroup(ObjectGuid guid, uint8 group) { member_witerator slot = _getMemberWSlot(guid); @@ -1725,8 +1723,8 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) if (slot == m_memberSlots.end()) return; + uint8 prevSubGroup = slot->group; // Abort if the player is already in the target sub group - uint8 prevSubGroup = GetMemberGroup(guid); if (prevSubGroup == group) return; @@ -1758,7 +1756,6 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) else { // If player is in BG raid, it is possible that he is also in normal raid - and that normal raid is stored in m_originalGroup reference - prevSubGroup = player->GetOriginalSubGroup(); player->GetOriginalGroupRef().setSubGroup(group); } } @@ -1767,6 +1764,51 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) SendUpdate(); } +void Group::SwapMembersGroups(ObjectGuid firstGuid, ObjectGuid secondGuid) +{ + if (!isRaidGroup()) + return; + + member_witerator slots[2]; + slots[0] = _getMemberWSlot(firstGuid); + slots[1] = _getMemberWSlot(secondGuid); + if (slots[0] == m_memberSlots.end() || slots[1] == m_memberSlots.end()) + return; + + if (slots[0]->group == slots[1]->group) + return; + + uint8 tmp = slots[0]->group; + slots[0]->group = slots[1]->group; + slots[1]->group = tmp; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + for (uint8 i = 0; i < 2; i++) + { + // Preserve new sub group in database for non-raid groups + if (!isBGGroup() && !isBFGroup()) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); + + stmt->setUInt8(0, slots[i]->group); + stmt->setUInt64(1, slots[i]->guid.GetCounter()); + + trans->Append(stmt); + } + + if (Player* player = ObjectAccessor::FindConnectedPlayer(slots[i]->guid)) + { + if (player->GetGroup() == this) + player->GetGroupRef().setSubGroup(slots[i]->group); + else + player->GetOriginalGroupRef().setSubGroup(slots[i]->group); + } + } + CharacterDatabase.CommitTransaction(trans); + + SendUpdate(); +} + // Retrieve the next Round-Roubin player for the group // // No update done if loot method is FFA. @@ -2262,9 +2304,167 @@ void Group::SetLfgRoles(ObjectGuid guid, uint8 roles) SendUpdate(); } +uint8 Group::GetLfgRoles(ObjectGuid guid) +{ + member_witerator slot = _getMemberWSlot(guid); + if (slot == m_memberSlots.end()) + return 0; + + return slot->roles; +} + +void Group::Update(uint32 diff) +{ + UpdateReadyCheck(diff); +} + +void Group::UpdateReadyCheck(uint32 diff) +{ + if (!m_readyCheckStarted) + return; + + m_readyCheckTimer -= diff; + if (m_readyCheckTimer <= 0) + EndReadyCheck(); +} + +void Group::StartReadyCheck(ObjectGuid starterGuid, int8 partyIndex, uint32 duration) +{ + if (m_readyCheckStarted) + return; + + member_witerator slot = _getMemberWSlot(starterGuid); + if (slot == m_memberSlots.end()) + return ; + + m_readyCheckStarted = true; + m_readyCheckTimer = duration; + + SetOfflineMembersReadyChecked(); + + SetMemberReadyChecked(&(*slot)); + + WorldPackets::Party::ReadyCheckStarted readyCheckStarted; + readyCheckStarted.PartyGUID = m_guid; + readyCheckStarted.PartyIndex = partyIndex; + readyCheckStarted.InitiatorGUID = starterGuid; + readyCheckStarted.Duration = duration; + BroadcastPacket(readyCheckStarted.Write(), false); +} + +void Group::EndReadyCheck(void) +{ + if (!m_readyCheckStarted) + return; + + m_readyCheckStarted = false; + m_readyCheckTimer = 0; + + ResetMemberReadyChecked(); + + WorldPackets::Party::ReadyCheckCompleted readyCheckCompleted; + readyCheckCompleted.PartyIndex = 0; + readyCheckCompleted.PartyGUID = m_guid; + BroadcastPacket(readyCheckCompleted.Write(), false); +} + +bool Group::IsReadyCheckCompleted(void) const +{ + for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) + if (!citr->readyChecked) + return false; + return true; +} + +void Group::SetMemberReadyCheck(ObjectGuid guid, bool ready) +{ + if (!m_readyCheckStarted) + return; + + member_witerator slot = _getMemberWSlot(guid); + if (slot != m_memberSlots.end()) + SetMemberReadyCheck(&(*slot), ready); +} + +void Group::SetMemberReadyCheck(MemberSlot* slot, bool ready) +{ + WorldPackets::Party::ReadyCheckResponse response; + response.PartyGUID = m_guid; + response.Player = slot->guid; + response.IsReady = ready; + BroadcastPacket(response.Write(), false); + + SetMemberReadyChecked(slot); +} + +void Group::SetOfflineMembersReadyChecked(void) +{ + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + { + Player* player = ObjectAccessor::FindConnectedPlayer(itr->guid); + if (!player || !player->GetSession()) + SetMemberReadyCheck(&(*itr), false); + } +} + +void Group::SetMemberReadyChecked(MemberSlot* slot) +{ + slot->readyChecked = true; + if (IsReadyCheckCompleted()) + EndReadyCheck(); +} + +void Group::ResetMemberReadyChecked(void) +{ + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + itr->readyChecked = false; +} + +void Group::AddRaidMarker(uint8 markerId, uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid) +{ + if (markerId >= RAID_MARKERS_COUNT || m_markers[markerId]) + return; + + m_activeMarkers |= (1 << markerId); + m_markers[markerId] = Trinity::make_unique<RaidMarker>(mapId, positionX, positionY, positionZ, transportGuid); + SendRaidMarkersChanged(); +} + +void Group::DeleteRaidMarker(uint8 markerId) +{ + if (markerId > RAID_MARKERS_COUNT) + return; + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; i++) + if (m_markers[i] && (markerId == i || markerId == RAID_MARKERS_COUNT)) + { + m_markers[i] = nullptr; + m_activeMarkers &= ~(1 << i); + } + + SendRaidMarkersChanged(); +} + +void Group::SendRaidMarkersChanged(WorldSession* session, int8 partyIndex) +{ + WorldPackets::Party::RaidMarkersChanged packet; + + packet.PartyIndex = partyIndex; + packet.ActiveMarkers = m_activeMarkers; + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; i++) + if (m_markers[i]) + packet.RaidMarkers.push_back(m_markers[i].get()); + + if (session) + session->SendPacket(packet.Write()); + else + BroadcastPacket(packet.Write(), false); +} + bool Group::IsFull() const { - return isRaidGroup() ? (m_memberSlots.size() >= MAXRAIDSIZE) : (m_memberSlots.size() >= MAXGROUPSIZE); + return isRaidGroup() ? (m_memberSlots.size() >= MAX_RAID_SIZE) : (m_memberSlots.size() >= MAX_GROUP_SIZE); } bool Group::isLFGGroup() const @@ -2371,10 +2571,9 @@ bool Group::SameSubGroup(ObjectGuid guid1, MemberSlot const* slot2) const bool Group::HasFreeSlotSubGroup(uint8 subgroup) const { - return (m_subGroupsCounts && m_subGroupsCounts[subgroup] < MAXGROUPSIZE); + return (m_subGroupsCounts && m_subGroupsCounts[subgroup] < MAX_GROUP_SIZE); } - uint8 Group::GetMemberGroup(ObjectGuid guid) const { member_citerator mslot = _getMemberCSlot(guid); @@ -2522,3 +2721,15 @@ void Group::ToggleGroupMemberFlag(member_witerator slot, uint8 flag, bool apply) slot->flags &= ~flag; } +void Group::SetEveryoneIsAssistant(bool apply) +{ + if (apply) + m_groupType = GroupType(m_groupType | GROUPTYPE_EVERYONE_ASSISTANT); + else + m_groupType = GroupType(m_groupType & ~GROUPTYPE_EVERYONE_ASSISTANT); + + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + ToggleGroupMemberFlag(itr, MEMBER_FLAG_ASSISTANT, apply); + + SendUpdate(); +} diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 4154f31a410..634d1f0f37b 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -24,6 +24,7 @@ #include "LootMgr.h" #include "QueryResult.h" #include "SharedDefines.h" +#include "Object.h" class Battlefield; class Battleground; @@ -38,10 +39,14 @@ class WorldSession; struct MapEntry; -#define MAXGROUPSIZE 5 -#define MAXRAIDSIZE 40 -#define MAX_RAID_SUBGROUPS MAXRAIDSIZE/MAXGROUPSIZE -#define TARGETICONCOUNT 8 +#define MAX_GROUP_SIZE 5 +#define MAX_RAID_SIZE 40 +#define MAX_RAID_SUBGROUPS MAX_RAID_SIZE / MAX_GROUP_SIZE + +#define TARGET_ICONS_COUNT 8 +#define RAID_MARKERS_COUNT 8 + +#define READYCHECK_DURATION 35000 enum RollVote { @@ -81,50 +86,59 @@ enum GroupMemberAssignment enum GroupType { - GROUPTYPE_NORMAL = 0x00, - GROUPTYPE_BG = 0x01, - GROUPTYPE_RAID = 0x02, - GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask - GROUPTYPE_LFG_RESTRICTED = 0x04, // Script_HasLFGRestrictions() - GROUPTYPE_LFG = 0x08, + GROUPTYPE_NORMAL = 0x00, + GROUPTYPE_BG = 0x01, + GROUPTYPE_RAID = 0x02, + GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask + GROUPTYPE_LFG_RESTRICTED = 0x04, // Script_HasLFGRestrictions() + GROUPTYPE_LFG = 0x08, + GROUPTYPE_EVERYONE_ASSISTANT = 0x40, // Script_IsEveryoneAssistant() (4.x) // 0x10, leave/change group?, I saw this flag when leaving group and after leaving BG while in group // GROUPTYPE_ONE_PERSON_PARTY = 0x20, 4.x Script_IsOnePersonParty() - // GROUPTYPE_EVERYONE_ASSISTANT = 0x40 4.x Script_IsEveryoneAssistant() }; enum GroupUpdateFlags { GROUP_UPDATE_FLAG_NONE = 0x00000000, // nothing - 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 + GROUP_UPDATE_FLAG_UNK704 = 0x00000001, // uint8[2] (unk) + GROUP_UPDATE_FLAG_STATUS = 0x00000002, // uint16 (GroupMemberStatusFlag) + GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000004, // uint8 (PowerType) + GROUP_UPDATE_FLAG_UNK322 = 0x00000008, // uint16 (unk) + GROUP_UPDATE_FLAG_CUR_HP = 0x00000010, // uint32 (HP) + GROUP_UPDATE_FLAG_MAX_HP = 0x00000020, // uint32 (max HP) + GROUP_UPDATE_FLAG_CUR_POWER = 0x00000040, // int16 (power value) + GROUP_UPDATE_FLAG_MAX_POWER = 0x00000080, // int16 (max power value) + GROUP_UPDATE_FLAG_LEVEL = 0x00000100, // uint16 (level value) + GROUP_UPDATE_FLAG_UNK200000 = 0x00000200, // int16 (unk) + GROUP_UPDATE_FLAG_ZONE = 0x00000400, // uint16 (zone id) + GROUP_UPDATE_FLAG_UNK2000000 = 0x00000800, // int16 (unk) + GROUP_UPDATE_FLAG_UNK4000000 = 0x00001000, // int32 (unk) + GROUP_UPDATE_FLAG_POSITION = 0x00002000, // uint16 (x), uint16 (y), uint16 (z) + GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00104000, // int32 (vehicle seat id) + GROUP_UPDATE_FLAG_AURAS = 0x00008000, // 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 = 0x00010000, // complex (pet) + GROUP_UPDATE_FLAG_PHASE = 0x00020000, // int32 (unk), uint32 (phase count), for (count) uint16(phaseId) + + GROUP_UPDATE_FULL = GROUP_UPDATE_FLAG_UNK704 | GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_POWER_TYPE | + GROUP_UPDATE_FLAG_UNK322 | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP | + GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER | GROUP_UPDATE_FLAG_LEVEL | + GROUP_UPDATE_FLAG_UNK200000 | GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_UNK2000000 | + GROUP_UPDATE_FLAG_UNK4000000 | GROUP_UPDATE_FLAG_POSITION | GROUP_UPDATE_FLAG_VEHICLE_SEAT | + GROUP_UPDATE_FLAG_AURAS | GROUP_UPDATE_FLAG_PET | GROUP_UPDATE_FLAG_PHASE // all known flags +}; + +enum GroupUpdatePetFlags +{ + GROUP_UPDATE_FLAG_PET_NONE = 0x00000000, // nothing + GROUP_UPDATE_FLAG_PET_GUID = 0x00000001, // ObjectGuid (pet guid) + GROUP_UPDATE_FLAG_PET_NAME = 0x00000002, // cstring (name, NULL terminated string) + GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00000004, // uint16 (model id) + GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00000008, // uint32 (HP) + GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00000010, // uint32 (max HP) + GROUP_UPDATE_FLAG_PET_AURAS = 0x00000020, // [see GROUP_UPDATE_FLAG_AURAS] + + GROUP_UPDATE_PET_FULL = 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_AURAS // all pet flags }; class Roll : public LootValidatorRef @@ -160,6 +174,18 @@ struct InstanceGroupBind InstanceGroupBind() : save(NULL), perm(false) { } }; +struct RaidMarker +{ + WorldLocation Location; + ObjectGuid TransportGUID; + + RaidMarker(uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid = ObjectGuid::Empty) + { + Location.WorldRelocate(mapId, positionX, positionY, positionZ); + TransportGUID = transportGuid; + } +}; + /** request member stats checken **/ /// @todo uninvite people that not accepted invite class Group @@ -169,9 +195,11 @@ class Group { ObjectGuid guid; std::string name; + uint8 _class; uint8 group; uint8 flags; uint8 roles; + bool readyChecked; }; typedef std::list<MemberSlot> MemberSlotList; typedef MemberSlotList::const_iterator member_citerator; @@ -197,7 +225,7 @@ class Group bool AddLeaderInvite(Player* player); bool AddMember(Player* player); bool RemoveMember(ObjectGuid guid, const RemoveMethod &method = GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker = ObjectGuid::Empty, const char* reason = NULL); - void ChangeLeader(ObjectGuid guid); + void ChangeLeader(ObjectGuid guid, int8 partyIndex = 0); void SetLootMethod(LootMethod method); void SetLooterGuid(ObjectGuid guid); void SetMasterLooterGuid(ObjectGuid guid); @@ -205,6 +233,31 @@ class Group void SetLootThreshold(ItemQualities threshold); void Disband(bool hideDestroy = false); void SetLfgRoles(ObjectGuid guid, uint8 roles); + uint8 GetLfgRoles(ObjectGuid guid); + void SetEveryoneIsAssistant(bool apply); + + // Update + void Update(uint32 diff); + void UpdateReadyCheck(uint32 diff); + + // Ready check + void StartReadyCheck(ObjectGuid starterGuid, int8 partyIndex, uint32 duration = READYCHECK_DURATION); + void EndReadyCheck(); + + bool IsReadyCheckStarted(void) const { return m_readyCheckStarted; } + bool IsReadyCheckCompleted(void) const; + + void SetOfflineMembersReadyChecked(void); + void SetMemberReadyCheck(ObjectGuid guid, bool ready); + void SetMemberReadyCheck(MemberSlot* slot, bool ready); + + void SetMemberReadyChecked(MemberSlot* slot); + void ResetMemberReadyChecked(void); + + // Raid Markers + void AddRaidMarker(uint8 markerId, uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid = ObjectGuid::Empty); + void DeleteRaidMarker(uint8 markerId); + void SendRaidMarkersChanged(WorldSession* session = nullptr, int8 partyIndex = 0); // properties accessories bool IsFull() const; @@ -221,7 +274,7 @@ class Group ObjectGuid GetMasterLooterGuid() const; ItemQualities GetLootThreshold() const; - uint32 GetDbStoreId() const { return m_dbStoreId; }; + uint32 GetDbStoreId() const { return m_dbStoreId; } // member manipulation methods bool IsMember(ObjectGuid guid) const; @@ -254,7 +307,8 @@ class Group GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot, ObjectGuid& errorGuid); void ChangeMembersGroup(ObjectGuid guid, uint8 group); - void SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid); + void SwapMembersGroups(ObjectGuid firstGuid, ObjectGuid secondGuid); + void SetTargetIcon(uint8 symbol, ObjectGuid target, ObjectGuid changedBy, uint8 partyIndex); void SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags flag); void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag); @@ -269,7 +323,7 @@ class Group // -no description- //void SendInit(WorldSession* session); - void SendTargetIconList(WorldSession* session); + void SendTargetIconList(WorldSession* session, int8 partyIndex = 0); void SendUpdate(); void SendUpdateToPlayer(ObjectGuid playerGUID, MemberSlot* slot = NULL); void UpdatePlayerOutOfRange(Player* player); @@ -290,8 +344,6 @@ class Group void BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignoredPlayer = ObjectGuid::Empty); void BroadcastAddonMessagePacket(WorldPacket const* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignore = ObjectGuid::Empty); - void BroadcastReadyCheck(WorldPacket const* packet); - void OfflineReadyCheck(); /*********************************************************/ /*** LOOT SYSTEM ***/ @@ -351,7 +403,7 @@ class Group Difficulty m_legacyRaidDifficulty; Battleground* m_bgGroup; Battlefield* m_bfGroup; - ObjectGuid m_targetIcons[TARGETICONCOUNT]; + ObjectGuid m_targetIcons[TARGET_ICONS_COUNT]; LootMethod m_lootMethod; ItemQualities m_lootThreshold; ObjectGuid m_looterGuid; @@ -363,5 +415,13 @@ class Group uint32 m_counter; // used only in SMSG_GROUP_LIST uint32 m_maxEnchantingLevel; uint32 m_dbStoreId; // Represents the ID used in database (Can be reused by other groups if group was disbanded) + + // Ready Check + bool m_readyCheckStarted; + int32 m_readyCheckTimer; + + // Raid markers + std::array<std::unique_ptr<RaidMarker>, RAID_MARKERS_COUNT> m_markers; + uint32 m_activeMarkers; }; #endif diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp index f0c764e7269..7fb239cec48 100644 --- a/src/server/game/Groups/GroupMgr.cpp +++ b/src/server/game/Groups/GroupMgr.cpp @@ -233,3 +233,10 @@ void GroupMgr::LoadGroups() TC_LOG_INFO("server.loading", ">> Loaded %u group-instance saves in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } } + +void GroupMgr::Update(uint32 diff) +{ + for (GroupContainer::iterator itr = GroupStore.begin(); itr != GroupStore.end(); itr++) + if (itr->second) + itr->second->Update(diff); +} diff --git a/src/server/game/Groups/GroupMgr.h b/src/server/game/Groups/GroupMgr.h index 6aafe77432c..2fdd6d978e9 100644 --- a/src/server/game/Groups/GroupMgr.h +++ b/src/server/game/Groups/GroupMgr.h @@ -50,6 +50,8 @@ public: void AddGroup(Group* group); void RemoveGroup(Group* group); + void Update(uint32 diff); + protected: ObjectGuid::LowType NextGroupId; diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index c5812999490..d4c6a0a680d 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -1602,11 +1602,11 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name) } // Invited player cannot be in another guild - /*if (pInvitee->GetGuildId()) + if (pInvitee->GetGuildId()) { SendCommandResult(session, GUILD_COMMAND_INVITE_PLAYER, ERR_ALREADY_IN_GUILD_S, name); return; - }*/ + } // Invited player cannot be invited if (pInvitee->GetGuildIdInvited()) @@ -2466,7 +2466,7 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { WorldPackets::Chat::Chat packet; - packet.Initalize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg); + packet.Initialize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg); WorldPacket const* data = packet.Write(); for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindConnectedPlayer()) @@ -2481,7 +2481,7 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std:: if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { WorldPackets::Chat::Chat packet; - packet.Initalize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, LANG_ADDON, session->GetPlayer(), nullptr, msg, 0, "", DEFAULT_LOCALE, prefix); + packet.Initialize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, LANG_ADDON, session->GetPlayer(), nullptr, msg, 0, "", DEFAULT_LOCALE, prefix); WorldPacket const* data = packet.Write(); for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindPlayer()) diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 56d865e5d06..7b22d46d67b 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -248,6 +248,14 @@ bool LoginQueryHolder::Initialize() stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES, stmt); + return res; } @@ -2566,25 +2574,18 @@ void WorldSession::SendCharRename(ResponseCodes result, WorldPackets::Character: void WorldSession::SendCharCustomize(ResponseCodes result, WorldPackets::Character::CharCustomizeInfo const* customizeInfo) { - /// @todo: fix 6.x implementation - (void)result; - (void)customizeInfo; - /* - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1 + 8 + customizeInfo.NewName.size() + 1 + 6); - data << uint8(result); if (result == RESPONSE_SUCCESS) { - data << customizeInfo.Guid; - data << customizeInfo.NewName; - data << uint8(customizeInfo.Gender); - data << uint8(customizeInfo.Skin); - data << uint8(customizeInfo.Face); - data << uint8(customizeInfo.HairStyle); - data << uint8(customizeInfo.HairColor); - data << uint8(customizeInfo.FacialHair); + WorldPackets::Character::CharCustomizeResponse response(customizeInfo); + SendPacket(response.Write()); + } + else + { + WorldPackets::Character::CharCustomizeFailed failed; + failed.Result = uint8(result); + failed.CharGUID = customizeInfo->CharGUID; + SendPacket(failed.Write()); } - SendPacket(&data); - */ } void WorldSession::SendCharFactionChange(ResponseCodes result, WorldPackets::Character::CharRaceOrFactionChangeInfo const* factionChangeInfo) diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index b5550c2c073..b9fd383b19d 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -288,7 +288,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPackets::Chat::Chat packet; - packet.Initalize(ChatMsg(type), Language(lang), sender, nullptr, msg); + packet.Initialize(ChatMsg(type), Language(lang), sender, nullptr, msg); group->BroadcastPacket(packet.Write(), false, group->GetMemberGroup(GetPlayer()->GetGUID())); break; } @@ -320,8 +320,8 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, } case CHAT_MSG_RAID: { - Group* group = GetPlayer()->GetOriginalGroup(); - if (!group) + Group* group = GetPlayer()->GetGroup(); + if (!group || !group->isRaidGroup() || group->isBGGroup()) return; if (group->IsLeader(GetPlayer()->GetGUID())) @@ -330,7 +330,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPackets::Chat::Chat packet; - packet.Initalize(ChatMsg(type), Language(lang), sender, nullptr, msg); + packet.Initialize(ChatMsg(type), Language(lang), sender, nullptr, msg); group->BroadcastPacket(packet.Write(), false); break; } @@ -344,7 +344,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, WorldPackets::Chat::Chat packet; //in battleground, raid warning is sent only to players in battleground - code is ok - packet.Initalize(CHAT_MSG_RAID_WARNING, Language(lang), sender, NULL, msg); + packet.Initialize(CHAT_MSG_RAID_WARNING, Language(lang), sender, NULL, msg); group->BroadcastPacket(packet.Write(), false); break; } @@ -381,7 +381,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPackets::Chat::Chat packet; - packet.Initalize(ChatMsg(type), Language(lang), sender, nullptr, msg); + packet.Initialize(ChatMsg(type), Language(lang), sender, nullptr, msg); group->BroadcastPacket(packet.Write(), false); break; } @@ -484,7 +484,7 @@ void WorldSession::HandleChatAddonMessage(ChatMsg type, std::string prefix, std: } WorldPackets::Chat::Chat packet; - packet.Initalize(type, LANG_ADDON, sender, nullptr, text, 0, "", DEFAULT_LOCALE, prefix); + packet.Initialize(type, LANG_ADDON, sender, nullptr, text, 0, "", DEFAULT_LOCALE, prefix); group->BroadcastAddonMessagePacket(packet.Write(), prefix, true, subGroup, sender->GetGUID()); break; } @@ -666,7 +666,7 @@ void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recvData) return; WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_IGNORED, LANG_UNIVERSAL, _player, _player, GetPlayer()->GetName()); + packet.Initialize(CHAT_MSG_IGNORED, LANG_UNIVERSAL, _player, _player, GetPlayer()->GetName()); player->SendDirectMessage(packet.Write()); } diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index 9552c9a0655..eefe89fef74 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -35,6 +35,7 @@ #include "SpellAuraEffects.h" #include "MiscPackets.h" #include "LootPackets.h" +#include "PartyPackets.h" class Aura; @@ -51,103 +52,59 @@ 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 + 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); -} - -void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) -{ - 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(); + WorldPackets::Party::PartyCommandResult packet; - recvData.ReadByteSeq(crossRealmGuid[4]); - recvData.ReadByteSeq(crossRealmGuid[7]); - recvData.ReadByteSeq(crossRealmGuid[6]); + packet.Name = member; + packet.Command = uint8(operation); + packet.Result = uint8(res); + packet.ResultData = val; + packet.ResultGUID = ObjectGuid::Empty; - 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)) - { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_BAD_PLAYER_NAME_S); - return; - } + SendPacket(packet.Write()); +} - Player* player = ObjectAccessor::FindPlayerByName(memberName); +void WorldSession::HandlePartyInviteOpcode(WorldPackets::Party::PartyInviteClient& packet) +{ + Player* player = ObjectAccessor::FindPlayerByName(packet.TargetName); // no player if (!player) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_BAD_PLAYER_NAME_S); + SendPartyResult(PARTY_OP_INVITE, packet.TargetName, 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, player->GetName(), 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, player->GetName(), 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, player->GetName(), ERR_TARGET_NOT_IN_INSTANCE_S); return; } // just ignore us if (player->GetInstanceId() != 0 && player->GetDungeonDifficultyID() != GetPlayer()->GetDungeonDifficultyID()) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_IGNORING_YOU_S); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_IGNORING_YOU_S); return; } if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUID())) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_IGNORING_YOU_S); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_IGNORING_YOU_S); return; } - ObjectGuid invitedGuid = player->GetGUID(); - Group* group = GetPlayer()->GetGroup(); if (group && group->isBGGroup()) group = GetPlayer()->GetOriginalGroup(); @@ -155,67 +112,18 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) Group* group2 = player->GetGroup(); if (group2 && group2->isBGGroup()) group2 = player->GetOriginalGroup(); + // 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, player->GetName(), 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_PARTY_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); + WorldPackets::Party::PartyInvite partyInvite; + partyInvite.Initialize(GetPlayer(), packet.ProposedRoles, false); + player->GetSession()->SendPacket(partyInvite.Write()); } return; @@ -264,79 +172,21 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) } } - // ok, we do it - WorldPacket data(SMSG_PARTY_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(); + WorldPackets::Party::PartyInvite partyInvite; + partyInvite.Initialize(GetPlayer(), packet.ProposedRoles, true); + player->GetSession()->SendPacket(partyInvite.Write()); - 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, player->GetName(), ERR_PARTY_RESULT_OK); } -void WorldSession::HandleGroupInviteResponseOpcode(WorldPacket& recvData) +void WorldSession::HandlePartyInviteResponseOpcode(WorldPackets::Party::PartyInviteResponse& packet) { - recvData.ReadBit(); // unk always 0 - bool accept = recvData.ReadBit(); - - // Never actually received? - /*if (accept) - recvData.read_skip<uint32>(); // unk*/ - Group* group = GetPlayer()->GetGroupInvite(); if (!group) return; - if (accept) + if (packet.Accept) { // Remove player from invitees in any case group->RemoveInvite(GetPlayer()); @@ -391,28 +241,22 @@ void WorldSession::HandleGroupInviteResponseOpcode(WorldPacket& recvData) return; // report - WorldPacket data(SMSG_GROUP_DECLINE, GetPlayer()->GetName().size()); - data << GetPlayer()->GetName(); - leader->GetSession()->SendPacket(&data); + WorldPackets::Party::GroupDecline decline(GetPlayer()->GetName()); + leader->GetSession()->SendPacket(decline.Write()); } } -void WorldSession::HandleGroupUninviteOpcode(WorldPacket& recvData) +void WorldSession::HandlePartyUninviteOpcode(WorldPackets::Party::PartyUninvite& packet) { - ObjectGuid guid; - std::string reason; - recvData >> guid; - recvData >> reason; - - //can't uninvite yourself - if (guid == GetPlayer()->GetGUID()) + // can't uninvite yourself + if (packet.TargetGUID == GetPlayer()->GetGUID()) { TC_LOG_ERROR("network", "WorldSession::HandleGroupUninviteGuidOpcode: leader %s (%s) tried to uninvite himself from the group.", GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); return; } - PartyResult res = GetPlayer()->CanUninviteFromGroup(guid); + PartyResult res = GetPlayer()->CanUninviteFromGroup(packet.TargetGUID); if (res != ERR_PARTY_RESULT_OK) { SendPartyResult(PARTY_OP_UNINVITE, "", res); @@ -423,13 +267,13 @@ void WorldSession::HandleGroupUninviteOpcode(WorldPacket& recvData) // grp is checked already above in CanUninviteFromGroup() ASSERT(grp); - if (grp->IsMember(guid)) + if (grp->IsMember(packet.TargetGUID)) { - Player::RemoveFromGroup(grp, guid, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID(), reason.c_str()); + Player::RemoveFromGroup(grp, packet.TargetGUID, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID(), packet.Reason.c_str()); return; } - if (Player* player = grp->GetInvited(guid)) + if (Player* player = grp->GetInvited(packet.TargetGUID)) { player->UninviteFromGroup(); return; @@ -438,12 +282,9 @@ void WorldSession::HandleGroupUninviteOpcode(WorldPacket& recvData) SendPartyResult(PARTY_OP_UNINVITE, "", ERR_TARGET_NOT_IN_GROUP_S); } -void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket& recvData) +void WorldSession::HandleSetPartyLeaderOpcode(WorldPackets::Party::SetPartyLeader& packet) { - ObjectGuid guid; - recvData >> guid; - - Player* player = ObjectAccessor::FindConnectedPlayer(guid); + Player* player = ObjectAccessor::FindConnectedPlayer(packet.TargetGUID); Group* group = GetPlayer()->GetGroup(); if (!group || !player) @@ -453,87 +294,35 @@ void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket& recvData) return; // Everything's fine, accepted. - group->ChangeLeader(guid); + group->ChangeLeader(packet.TargetGUID, packet.PartyIndex); group->SendUpdate(); } -void WorldSession::HandleGroupSetRolesOpcode(WorldPacket& recvData) +void WorldSession::HandleSetRoleOpcode(WorldPackets::Party::SetRole& packet) { - 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_ROLE_CHANGED_INFORM, 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 (Group* group = GetPlayer()->GetGroup()) + WorldPackets::Party::RoleChangedInform roleChangedInform; + + Group* group = GetPlayer()->GetGroup(); + uint8 oldRole = group ? group->GetLfgRoles(packet.TargetGUID) : 0; + if (oldRole == packet.Role) + return; + + roleChangedInform.PartyIndex = packet.PartyIndex; + roleChangedInform.From = GetPlayer()->GetGUID(); + roleChangedInform.ChangedUnit = packet.TargetGUID; + roleChangedInform.OldRole = oldRole; + roleChangedInform.NewRole = packet.Role; + + if (group) { - /// @todo probably should be sent only if (oldRole != newRole) - group->BroadcastPacket(&data, false); - group->SetLfgRoles(guid2, newRole); + group->BroadcastPacket(roleChangedInform.Write(), false); + group->SetLfgRoles(packet.TargetGUID, packet.Role); } else - SendPacket(&data); + SendPacket(roleChangedInform.Write()); } -void WorldSession::HandleGroupDisbandOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleLeaveGroupOpcode(WorldPackets::Party::LeaveGroup& /*packet*/) { Group* grp = GetPlayer()->GetGroup(); if (!grp) @@ -554,13 +343,8 @@ void WorldSession::HandleGroupDisbandOpcode(WorldPacket& /*recvData*/) GetPlayer()->RemoveFromGroup(GROUP_REMOVEMETHOD_LEAVE); } -void WorldSession::HandleLootMethodOpcode(WorldPacket& recvData) +void WorldSession::HandleSetLootMethodOpcode(WorldPackets::Party::SetLootMethod& packet) { - uint32 lootMethod; - ObjectGuid lootMaster; - uint32 lootThreshold; - recvData >> lootMethod >> lootMaster >> lootThreshold; - Group* group = GetPlayer()->GetGroup(); if (!group) return; @@ -569,20 +353,20 @@ void WorldSession::HandleLootMethodOpcode(WorldPacket& recvData) if (!group->IsLeader(GetPlayer()->GetGUID())) return; - if (lootMethod > NEED_BEFORE_GREED) + if (packet.LootMethod > NEED_BEFORE_GREED) return; - if (lootThreshold < ITEM_QUALITY_UNCOMMON || lootThreshold > ITEM_QUALITY_ARTIFACT) + if (packet.LootThreshold < ITEM_QUALITY_UNCOMMON || packet.LootThreshold > ITEM_QUALITY_ARTIFACT) return; - if (lootMethod == MASTER_LOOT && !group->IsMember(lootMaster)) + if (packet.LootMethod == MASTER_LOOT && !group->IsMember(packet.LootMasterGUID)) return; /********************/ // everything's fine, do it - group->SetLootMethod((LootMethod)lootMethod); - group->SetMasterLooterGuid(lootMaster); - group->SetLootThreshold((ItemQualities)lootThreshold); + group->SetLootMethod((LootMethod)packet.LootMethod); + group->SetMasterLooterGuid(packet.LootMasterGUID); + group->SetLootThreshold((ItemQualities)packet.LootThreshold); group->SendUpdate(); } @@ -605,28 +389,16 @@ void WorldSession::HandleLootRoll(WorldPackets::Loot::LootRoll& packet) } } -void WorldSession::HandleMinimapPingOpcode(WorldPacket& recvData) +void WorldSession::HandleMinimapPingOpcode(WorldPackets::Party::MinimapPingClient& packet) { - TC_LOG_DEBUG("network", "WORLD: Received MSG_MINIMAP_PING"); - if (!GetPlayer()->GetGroup()) return; - float x, y; - recvData >> x; - recvData >> y; - - //TC_LOG_DEBUG("misc", "Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y); - - /** error handling **/ - /********************/ - - // everything's fine, do it - WorldPacket data(SMSG_MINIMAP_PING, (8+4+4)); - data << GetPlayer()->GetGUID(); - data << float(x); - data << float(y); - GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID()); + WorldPackets::Party::MinimapPing minimapPing; + minimapPing.Sender = GetPlayer()->GetGUID(); + minimapPing.PositionX = packet.PositionX; + minimapPing.PositionY = packet.PositionY; + GetPlayer()->GetGroup()->BroadcastPacket(minimapPing.Write(), true, -1, GetPlayer()->GetGUID()); } void WorldSession::HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& packet) @@ -643,8 +415,6 @@ void WorldSession::HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& // everything's fine, do it roll = urand(minimum, maximum); - //TC_LOG_DEBUG("misc", "ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll); - WorldPackets::Misc::RandomRoll randomRoll; randomRoll.Min = minimum; randomRoll.Max = maximum; @@ -657,44 +427,31 @@ void WorldSession::HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& SendPacket(randomRoll.Write()); } -void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket& recvData) +void WorldSession::HandleUpdateRaidTargetOpcode(WorldPackets::Party::UpdateRaidTarget& packet) { - TC_LOG_DEBUG("network", "WORLD: Received MSG_RAID_TARGET_UPDATE"); - Group* group = GetPlayer()->GetGroup(); if (!group) return; - uint8 x; - recvData >> x; - - /** error handling **/ - /********************/ - - // everything's fine, do it - if (x == 0xFF) // target icon request - group->SendTargetIconList(this); - else // target icon update + if (packet.Symbol == 0xFF) // target icon request + group->SendTargetIconList(this, packet.PartyIndex); + else // target icon update { if (group->isRaidGroup() && !group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) return; - ObjectGuid guid; - recvData >> guid; - - if (guid.IsPlayer()) + if (packet.Target.IsPlayer()) { - Player* target = ObjectAccessor::FindConnectedPlayer(guid); - + Player* target = ObjectAccessor::FindConnectedPlayer(packet.Target); if (!target || target->IsHostileTo(GetPlayer())) return; } - group->SetTargetIcon(x, _player->GetGUID(), guid); + group->SetTargetIcon(packet.Symbol, packet.Target, GetPlayer()->GetGUID(), packet.PartyIndex); } } -void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket& recvData) +void WorldSession::HandleConvertRaidOpcode(WorldPackets::Party::ConvertRaid& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) @@ -711,71 +468,56 @@ void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket& recvData) SendPartyResult(PARTY_OP_INVITE, "", ERR_PARTY_RESULT_OK); // 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) + if (packet.Raid) group->ConvertToRaid(); else group->ConvertToGroup(); } -void WorldSession::HandleGroupRequestJoinUpdates(WorldPacket& /*recvData*/) +void WorldSession::HandleRequestPartyJoinUpdates(WorldPackets::Party::RequestPartyJoinUpdates& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) return; - // does some stuff. dunno what. + group->SendTargetIconList(this, packet.PartyIndex); + group->SendRaidMarkersChanged(this, packet.PartyIndex); } -void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket& recvData) +void WorldSession::HandleChangeSubGroupOpcode(WorldPackets::Party::ChangeSubGroup& packet) { // we will get correct pointer for group here, so we don't have to check if group is BG raid Group* group = GetPlayer()->GetGroup(); if (!group) return; - std::string name; - uint8 groupNr; - recvData >> name; - recvData >> groupNr; - - if (groupNr >= MAX_RAID_SUBGROUPS) + if (packet.NewSubGroup >= MAX_RAID_SUBGROUPS) return; ObjectGuid senderGuid = GetPlayer()->GetGUID(); if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) return; - if (!group->HasFreeSlotSubGroup(groupNr)) + if (!group->HasFreeSlotSubGroup(packet.NewSubGroup)) return; - Player* movedPlayer = ObjectAccessor::FindConnectedPlayerByName(name); - ObjectGuid guid; - - if (movedPlayer) - guid = movedPlayer->GetGUID(); - else - { - CharacterDatabase.EscapeString(name); - guid = ObjectMgr::GetPlayerGUIDByName(name.c_str()); - } - - group->ChangeMembersGroup(guid, groupNr); + group->ChangeMembersGroup(packet.TargetGUID, packet.NewSubGroup); } -void WorldSession::HandleGroupSwapSubGroupOpcode(WorldPacket& recvData) +void WorldSession::HandleSwapSubGroupsOpcode(WorldPackets::Party::SwapSubGroups& packet) { - std::string unk1; - std::string unk2; + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; - recvData >> unk1; - recvData >> unk2; + ObjectGuid senderGuid = GetPlayer()->GetGUID(); + if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) + return; + + group->SwapMembersGroups(packet.FirstTarget, packet.SecondTarget); } -void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket& recvData) +void WorldSession::HandleSetAssistantLeaderOpcode(WorldPackets::Party::SetAssistantLeader& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) @@ -784,12 +526,7 @@ void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket& recvData) if (!group->IsLeader(GetPlayer()->GetGUID())) return; - ObjectGuid guid; - bool apply; - recvData >> guid; - recvData >> apply; - - group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_ASSISTANT); + group->SetGroupMemberFlag(packet.Target, packet.Apply, MEMBER_FLAG_ASSISTANT); } void WorldSession::HandlePartyAssignmentOpcode(WorldPacket& recvData) @@ -826,509 +563,102 @@ void WorldSession::HandlePartyAssignmentOpcode(WorldPacket& recvData) group->SendUpdate(); } -void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket& recvData) +void WorldSession::HandleDoReadyCheckOpcode(WorldPackets::Party::DoReadyCheck& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) return; - if (recvData.empty()) // request - { - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - return; - /********************/ - - // everything's fine, do it - WorldPacket data(SMSG_READY_CHECK_STARTED, 8); - data << GetPlayer()->GetGUID(); - group->BroadcastPacket(&data, false, -1); + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return; + /********************/ - group->OfflineReadyCheck(); - } - else // answer - { - uint8 state; - recvData >> state; - - // everything's fine, do it - WorldPacket data(SMSG_READY_CHECK_RESPONSE, 9); - data << GetPlayer()->GetGUID(); - data << uint8(state); - group->BroadcastReadyCheck(&data); - } + // everything's fine, do it + group->StartReadyCheck(GetPlayer()->GetGUID(), packet.PartyIndex); } -void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data) +void WorldSession::HandleReadyCheckResponseOpcode(WorldPackets::Party::ReadyCheckResponseClient& packet) { - uint32 mask = player->GetGroupUpdateFlag(); - - if (mask == GROUP_UPDATE_FLAG_NONE) + Group* group = GetPlayer()->GetGroup(); + if (!group) 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); - - data->Initialize(SMSG_PARTY_MEMBER_STATE, 80); // average value - *data << player->GetPackGUID(); - *data << uint32(mask); - - if (mask & GROUP_UPDATE_FLAG_STATUS) - { - uint16 playerStatus = MEMBER_STATUS_ONLINE; - if (player->IsPvP()) - playerStatus |= MEMBER_STATUS_PVP; - - if (!player->IsAlive()) - { - if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - playerStatus |= MEMBER_STATUS_GHOST; - else - playerStatus |= MEMBER_STATUS_DEAD; - } - - if (player->IsFFAPvP()) - playerStatus |= MEMBER_STATUS_PVP_FFA; - - if (player->isAFK()) - playerStatus |= MEMBER_STATUS_AFK; - - if (player->isDND()) - playerStatus |= MEMBER_STATUS_DND; - - *data << uint16(playerStatus); - } - - if (mask & GROUP_UPDATE_FLAG_CUR_HP) - *data << uint32(player->GetHealth()); - - if (mask & GROUP_UPDATE_FLAG_MAX_HP) - *data << uint32(player->GetMaxHealth()); - - Powers powerType = player->getPowerType(); - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) - *data << uint8(powerType); - - if (mask & GROUP_UPDATE_FLAG_CUR_POWER) - *data << uint16(player->GetPower(powerType)); - - if (mask & GROUP_UPDATE_FLAG_MAX_POWER) - *data << uint16(player->GetMaxPower(powerType)); - - if (mask & GROUP_UPDATE_FLAG_LEVEL) - *data << uint16(player->getLevel()); - - 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); - if (!aurApp) - { - *data << uint32(0); - *data << uint16(0); - continue; - } - - *data << uint32(aurApp->GetBase()->GetId()); - *data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_SCALABLE) - { - 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); - } - } - } - } - } - - Pet* pet = player->GetPet(); - if (mask & GROUP_UPDATE_FLAG_PET_GUID) - { - if (pet) - *data << pet->GetGUID(); - else - *data << ObjectGuid::Empty; - } - - if (mask & GROUP_UPDATE_FLAG_PET_NAME) - { - if (pet) - *data << pet->GetName(); - else - *data << uint8(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) - { - if (pet) - *data << uint16(pet->GetDisplayId()); - else - *data << uint16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) - { - if (pet) - *data << uint32(pet->GetHealth()); - else - *data << uint32(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) - { - if (pet) - *data << uint32(pet->GetMaxHealth()); - else - *data << uint32(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) - { - if (pet) - *data << uint8(pet->getPowerType()); - else - *data << uint8(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) - { - if (pet) - *data << uint16(pet->GetPower(pet->getPowerType())); - else - *data << uint16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) - { - if (pet) - *data << uint16(pet->GetMaxPower(pet->getPowerType())); - else - *data << uint16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_AURAS) - { - 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); - if (!aurApp) - { - *data << uint32(0); - *data << uint16(0); - continue; - } - - *data << uint32(aurApp->GetBase()->GetId()); - *data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_SCALABLE) - { - 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) - { - if (Vehicle* veh = player->GetVehicle()) - *data << uint32(veh->GetVehicleInfo()->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); - } + // everything's fine, do it + group->SetMemberReadyCheck(GetPlayer()->GetGUID(), packet.IsReady); } -/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ -void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) +void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPackets::Party::RequestPartyMemberStats& packet) { - ObjectGuid Guid; - recvData >> Guid; + WorldPackets::Party::PartyMemberStats partyMemberStats; - Player* player = ObjectAccessor::FindConnectedPlayer(Guid); + Player* player = ObjectAccessor::FindConnectedPlayer(packet.TargetGUID); if (!player) { - WorldPacket data(SMSG_PARTY_MEMBER_STATE, 3 + 4 + 2); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data << Guid.WriteAsPacked(); - data << uint32(GROUP_UPDATE_FLAG_STATUS); - data << uint16(MEMBER_STATUS_OFFLINE); - SendPacket(&data); - return; - } - - Pet* pet = player->GetPet(); - Powers powerType = player->getPowerType(); - std::set<uint32> const& phases = player->GetPhases(); - - WorldPacket data(SMSG_PARTY_MEMBER_STATE, 4 + 2 + 2 + 2 + 1 + 2 * 6 + 8 + 1 + 8); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data << player->GetPackGUID(); - - uint32 updateFlags = GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP - | 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_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | GROUP_UPDATE_FLAG_PET_AURAS; - - if (powerType != POWER_MANA) - updateFlags |= GROUP_UPDATE_FLAG_POWER_TYPE; - - if (pet) - updateFlags |= GROUP_UPDATE_FLAG_PET_GUID | 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; - - 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; - - if (!player->IsAlive()) - { - if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - playerStatus |= MEMBER_STATUS_GHOST; - else - playerStatus |= MEMBER_STATUS_DEAD; - } - - if (player->IsFFAPvP()) - playerStatus |= MEMBER_STATUS_PVP_FFA; - - if (player->isAFK()) - playerStatus |= MEMBER_STATUS_AFK; - - if (player->isDND()) - playerStatus |= MEMBER_STATUS_DND; - - data << uint32(updateFlags); - data << uint16(playerStatus); // GROUP_UPDATE_FLAG_STATUS - data << uint32(player->GetHealth()); // GROUP_UPDATE_FLAG_CUR_HP - data << uint32(player->GetMaxHealth()); // GROUP_UPDATE_FLAG_MAX_HP - if (updateFlags & GROUP_UPDATE_FLAG_POWER_TYPE) - data << uint8(powerType); - - data << uint16(player->GetPower(powerType)); // GROUP_UPDATE_FLAG_CUR_POWER - data << uint16(player->GetMaxPower(powerType)); // GROUP_UPDATE_FLAG_MAX_POWER - data << uint16(player->getLevel()); // GROUP_UPDATE_FLAG_LEVEL - 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 - - // GROUP_UPDATE_FLAG_AURAS - data << uint8(1); - uint64 auramask = 0; - size_t maskPos = data.wpos(); - 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); - - data << uint32(aurApp->GetBase()->GetId()); - data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_SCALABLE) - { - 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 - - if (updateFlags & GROUP_UPDATE_FLAG_PET_GUID) - data << pet->GetGUID(); - - data << std::string(pet ? pet->GetName() : ""); // GROUP_UPDATE_FLAG_PET_NAME - data << uint16(pet ? pet->GetDisplayId() : 0); // GROUP_UPDATE_FLAG_PET_MODEL_ID - - if (updateFlags & GROUP_UPDATE_FLAG_PET_CUR_HP) - data << uint32(pet->GetHealth()); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_MAX_HP) - data << uint32(pet->GetMaxHealth()); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_POWER_TYPE) - data << (uint8)pet->getPowerType(); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_CUR_POWER) - data << uint16(pet->GetPower(pet->getPowerType())); - - 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); - - data << uint32(aurApp->GetBase()->GetId()); - data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_SCALABLE) - { - 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, petAuraMask); // GROUP_UPDATE_FLAG_PET_AURAS - - if (updateFlags & GROUP_UPDATE_FLAG_VEHICLE_SEAT) - data << uint32(player->GetVehicle()->GetVehicleInfo()->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); + partyMemberStats.MemberStats.GUID = packet.TargetGUID; + partyMemberStats.MemberStats.Status = MEMBER_STATUS_OFFLINE; } + else + partyMemberStats.Initialize(player); - SendPacket(&data); + SendPacket(partyMemberStats.Write()); } -void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleRequestRaidInfoOpcode(WorldPackets::Party::RequestRaidInfo& /*packet*/) { // every time the player checks the character screen _player->SendRaidInfo(); } -void WorldSession::HandleOptOutOfLootOpcode(WorldPacket& recvData) +void WorldSession::HandleOptOutOfLootOpcode(WorldPackets::Party::OptOutOfLoot& packet) { - bool passOnLoot; - recvData >> passOnLoot; // 1 always pass, 0 do not pass - // ignore if player not loaded if (!GetPlayer()) // needed because STATUS_AUTHED { - if (passOnLoot) + if (packet.PassOnLoot) TC_LOG_ERROR("network", "CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!"); return; } - GetPlayer()->SetPassOnGroupLoot(passOnLoot != 0); + GetPlayer()->SetPassOnGroupLoot(packet.PassOnLoot); } -void WorldSession::HandleRolePollBeginOpcode(WorldPacket& recvData) +void WorldSession::HandleInitiateRolePoll(WorldPackets::Party::InitiateRolePoll& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) return; - if (recvData.empty()) - { - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - return; + ObjectGuid guid = GetPlayer()->GetGUID(); + if (!group->IsLeader(guid) && !group->IsAssistant(guid)) + return; - ObjectGuid guid = GetPlayer()->GetGUID(); - - WorldPacket data(SMSG_ROLE_POLL_INFORM, 8); - data.WriteBit(guid[1]); - data.WriteBit(guid[5]); - data.WriteBit(guid[7]); - data.WriteBit(guid[3]); - data.WriteBit(guid[2]); - data.WriteBit(guid[4]); - data.WriteBit(guid[0]); - data.WriteBit(guid[6]); - data.WriteByteSeq(guid[4]); - data.WriteByteSeq(guid[7]); - data.WriteByteSeq(guid[0]); - data.WriteByteSeq(guid[5]); - data.WriteByteSeq(guid[1]); - data.WriteByteSeq(guid[6]); - data.WriteByteSeq(guid[2]); - data.WriteByteSeq(guid[3]); - - GetPlayer()->GetGroup()->BroadcastPacket(&data, true); - } + WorldPackets::Party::RolePollInform rolePollInform; + rolePollInform.From = GetPlayer()->GetGUID(); + rolePollInform.PartyIndex = packet.PartyIndex; + group->BroadcastPacket(rolePollInform.Write(), true); +} + +void WorldSession::HandleSetEveryoneIsAssistant(WorldPackets::Party::SetEveryoneIsAssistant& packet) +{ + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (!group->IsLeader(GetPlayer()->GetGUID())) + return; + + group->SetEveryoneIsAssistant(packet.EveryoneIsAssistant); +} + +void WorldSession::HandleClearRaidMarker(WorldPackets::Party::ClearRaidMarker& packet) +{ + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (group->isRaidGroup() && !group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return; + + group->DeleteRaidMarker(packet.MarkerId); } diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index c938751e162..e6aecff9137 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -716,13 +716,12 @@ void WorldSession::SendEnchantmentLog(ObjectGuid target, ObjectGuid caster, uint void WorldSession::SendItemEnchantTimeUpdate(ObjectGuid Playerguid, ObjectGuid Itemguid, uint32 slot, uint32 Duration) { - // last check 2.0.10 - WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8)); - data << Itemguid; - data << uint32(slot); - data << uint32(Duration); - data << Playerguid; - SendPacket(&data); + WorldPackets::Item::ItemEnchantTimeUpdate data; + data.ItemGuid = Itemguid; + data.DurationLeft = Duration; + data.Slot = slot; + data.OwnerGuid = Playerguid; + SendPacket(data.Write()); } void WorldSession::HandleWrapItem(WorldPackets::Item::WrapItem& packet) diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index c4d3358a333..4a3866cbb1b 100644 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -86,7 +86,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) { if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER) || (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() && - (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) + (GetPlayer()->GetGroup()->GetMembersCount() == MAX_GROUP_SIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) { recvData.rfinish(); return; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 025bb45b42b..c87bff8511e 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1213,129 +1213,29 @@ void WorldSession::HandleObjectUpdateRescuedOpcode(WorldPackets::Misc::ObjectUpd _player->m_clientGUIDs.insert(objectUpdateRescued.ObjectGUID); } -void WorldSession::HandleSaveCUFProfiles(WorldPacket& recvPacket) +void WorldSession::HandleSaveCUFProfiles(WorldPackets::Misc::SaveCUFProfiles& packet) { - uint8 count = (uint8)recvPacket.ReadBits(20); - - if (count > MAX_CUF_PROFILES) + if (packet.CUFProfiles.size() > 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 = 0; i < packet.CUFProfiles.size(); ++i) + GetPlayer()->SaveCUFProfile(i, std::move(packet.CUFProfiles[i])); - for (uint8 i = count; i < MAX_CUF_PROFILES; ++i) - GetPlayer()->SaveCUFProfile(i, NULL); + for (uint8 i = packet.CUFProfiles.size(); i < MAX_CUF_PROFILES; ++i) + GetPlayer()->SaveCUFProfile(i, nullptr); } void WorldSession::SendLoadCUFProfiles() { Player* player = GetPlayer(); - uint8 count = player->GetCUFProfilesCount(); + WorldPackets::Misc::LoadCUFProfiles loadCUFProfiles; - 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); + for (uint8 i = 0; i < MAX_CUF_PROFILES; i++) + if (CUFProfile* cufProfile = player->GetCUFProfile(i)) + loadCUFProfiles.CUFProfiles.push_back(cufProfile); + SendPacket(loadCUFProfiles.Write()); } diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 7f1782ea1f0..429d3565052 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -616,8 +616,7 @@ void WorldSession::HandlePetRename(WorldPacket& recvData) pet->SetName(name); - if (pet->GetOwner()->GetGroup()) - pet->GetOwner()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 3d2f60929fb..2d3090825da 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -281,8 +281,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast) caster = _player; } - // check known spell - if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id)) + // check known spell or raid marker spell (which not requires player to know it) + if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->HasEffect(SPELL_EFFECT_CHANGE_RAID_MARKER)) return; // Check possible spell cast overrides diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index a63ed66446e..189b620b805 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -155,12 +155,6 @@ uint32 LootStore::LoadLootTable() uint8 mincount = fields[7].GetUInt8(); uint8 maxcount = fields[8].GetUInt8(); - if (maxcount > std::numeric_limits<uint8>::max()) - { - TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: MaxCount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount, std::numeric_limits<uint8>::max()); - continue; // error already printed to log/console. - } - if (groupid >= 1 << 7) // it stored in 7 bit field { TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: GroupId (%u) must be less %u - skipped", GetName(), entry, item, groupid, 1 << 7); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index a2faa8cc0a0..fb1ac3cc62d 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -699,7 +699,7 @@ class Map : public GridRefManager<NGridType> { auto itr = _guidGenerators.find(high); if (itr == _guidGenerators.end()) - itr = _guidGenerators.insert(std::make_pair(high, std::unique_ptr<ObjectGuidGenerator<high>>(new ObjectGuidGenerator<high>()))).first; + itr = _guidGenerators.insert(std::make_pair(high, Trinity::make_unique<ObjectGuidGenerator<high>>())).first; return *itr->second; } diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 473e3163216..bd69844ae7c 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -214,7 +214,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, // some instances only have one difficulty GetDownscaledMapDifficultyData(GetId(), difficulty); - TC_LOG_DEBUG("maps", "MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); + TC_LOG_DEBUG("maps", "MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save ? "" : "new ", InstanceId, GetId(), difficulty ? "heroic" : "normal"); InstanceMap* map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this); ASSERT(map->IsDungeon()); diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index d8dba57d438..fd52bdd4c14 100644 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -29,8 +29,8 @@ class ZoneScript ZoneScript() { } virtual ~ZoneScript() { } - virtual uint32 GetCreatureEntry(uint32 /*guidlow*/, CreatureData const* data) { return data->id; } - virtual uint32 GetGameObjectEntry(uint32 /*guidlow*/, uint32 entry) { return entry; } + virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) { return data->id; } + virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) { return entry; } virtual void OnCreatureCreate(Creature* ) { } virtual void OnCreatureRemove(Creature* ) { } diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index ed004c6174d..86e1c80bbd1 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -1113,7 +1113,7 @@ enum SpellEffectName SPELL_EFFECT_REPUTATION = 103, SPELL_EFFECT_SUMMON_OBJECT_SLOT1 = 104, SPELL_EFFECT_SUMMON_OBJECT_SLOT2 = 105, - SPELL_EFFECT_SUMMON_OBJECT_SLOT3 = 106, + SPELL_EFFECT_CHANGE_RAID_MARKER = 106, SPELL_EFFECT_SUMMON_OBJECT_SLOT4 = 107, SPELL_EFFECT_DISPEL_MECHANIC = 108, SPELL_EFFECT_RESURRECT_PET = 109, @@ -1174,7 +1174,7 @@ enum SpellEffectName SPELL_EFFECT_REMOVE_AURA = 164, SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT = 165, SPELL_EFFECT_GIVE_CURRENCY = 166, - SPELL_EFFECT_167 = 167, + SPELL_EFFECT_UPDATE_PLAYER_PHASE = 167, SPELL_EFFECT_ALLOW_CONTROL_PET = 168, // NYI SPELL_EFFECT_DESTROY_ITEM = 169, SPELL_EFFECT_UPDATE_ZONE_AURAS_AND_PHASES = 170, // NYI diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 0b547d96e7f..c8da50364ba 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -182,7 +182,7 @@ class MotionMaster //: private std::stack<MovementGenerator *> void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ); void MoveJumpTo(float angle, float speedXY, float speedZ); void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP) - { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); }; + { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); } void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = EVENT_JUMP); void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount); void MoveFall(uint32 id = 0); diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index c878287b4ac..148cdeab68e 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -34,7 +34,7 @@ Quest::Quest(Field* questRecord) SuggestedPlayers = questRecord[7].GetUInt8(); NextQuestInChain = questRecord[8].GetUInt32(); RewardXPDifficulty = questRecord[9].GetUInt32(); - Float10 = questRecord[10].GetFloat(); + RewardXPMultiplier = questRecord[10].GetFloat(); RewardMoney = questRecord[11].GetUInt32(); RewardMoneyDifficulty = questRecord[12].GetUInt32(); Float13 = questRecord[13].GetFloat(); @@ -225,7 +225,7 @@ uint32 Quest::XPValue(uint32 playerLevel) const else if (diffFactor > 10) diffFactor = 10; - uint32 xp = diffFactor * xpentry->Exp[RewardXPDifficulty] / 10; + uint32 xp = diffFactor * xpentry->Exp[RewardXPDifficulty] * RewardXPMultiplier / 10; if (xp <= 100) xp = 5 * ((xp + 2) / 5); else if (xp <= 500) diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 8433a549c60..e11794dc64c 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -226,7 +226,8 @@ enum QuestObjectiveType QUEST_OBJECTIVE_AREATRIGGER = 10, QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC = 11, QUEST_OBJECTIVE_DEFEATBATTLEPET = 12, - QUEST_OBJECTIVE_WINPVPPETBATTLES = 13 + QUEST_OBJECTIVE_WINPVPPETBATTLES = 13, + QUEST_OBJECTIVE_CRITERIA_TREE = 14 }; struct QuestTemplateLocale @@ -318,6 +319,7 @@ class Quest uint32 GetBonusTalents() const { return RewardTalents; } int32 GetRewArenaPoints() const {return RewardArenaPoints; } uint32 GetXPDifficulty() const { return RewardXPDifficulty; } + float GetXPMultiplier() const { return RewardXPMultiplier; } uint32 GetSrcItemId() const { return SourceItemId; } uint32 GetSrcItemCount() const { return SourceItemIdCount; } uint32 GetSrcSpell() const { return SourceSpellID; } @@ -332,7 +334,7 @@ class Quest std::string const& GetPortraitGiverName() const { return PortraitGiverName; } std::string const& GetPortraitTurnInText() const { return PortraitTurnInText; } std::string const& GetPortraitTurnInName() const { return PortraitTurnInName; } - QuestObjectives const& GetObjectives() const { return Objectives; }; + QuestObjectives const& GetObjectives() const { return Objectives; } uint32 GetRewMoney() const; uint32 GetRewMoneyDifficulty() const { return RewardMoneyDifficulty; } uint32 GetRewHonor() const { return RewardHonor; } @@ -401,7 +403,7 @@ class Quest uint32 SuggestedPlayers; uint32 NextQuestInChain; uint32 RewardXPDifficulty; - float Float10; + float RewardXPMultiplier; int32 RewardMoney; uint32 RewardMoneyDifficulty; float Float13; diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 553c752ccce..aa8be4946e4 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -634,6 +634,7 @@ void AddSC_instance_magtheridons_lair(); void AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls void AddSC_boss_warbringer_omrogg(); void AddSC_boss_warchief_kargath_bladefist(); +void AddSC_shattered_halls(); void AddSC_instance_shattered_halls(); void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts void AddSC_boss_omor_the_unscarred(); @@ -1188,6 +1189,7 @@ void AddOutlandScripts() AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls AddSC_boss_warbringer_omrogg(); AddSC_boss_warchief_kargath_bladefist(); + AddSC_shattered_halls(); AddSC_instance_shattered_halls(); AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts AddSC_boss_omor_the_unscarred(); diff --git a/src/server/game/Server/Packets/ChannelPackets.h b/src/server/game/Server/Packets/ChannelPackets.h index 6c43588e86a..8dba1e84677 100644 --- a/src/server/game/Server/Packets/ChannelPackets.h +++ b/src/server/game/Server/Packets/ChannelPackets.h @@ -104,8 +104,8 @@ namespace WorldPackets ObjectGuid AddedUserGUID; - ChannelFlags ChannelFlags = CHANNEL_FLAG_NONE; - ChannelMemberFlags UserFlags = MEMBER_FLAG_NONE; + uint8 ChannelFlags = CHANNEL_FLAG_NONE; + uint8 UserFlags = MEMBER_FLAG_NONE; int32 ChannelID = 0; @@ -121,7 +121,7 @@ namespace WorldPackets ObjectGuid RemovedUserGUID; - ChannelFlags ChannelFlags = CHANNEL_FLAG_NONE; + uint8 ChannelFlags = CHANNEL_FLAG_NONE; uint32 ChannelID = 0; @@ -137,8 +137,8 @@ namespace WorldPackets ObjectGuid UpdatedUserGUID; - ChannelFlags ChannelFlags = CHANNEL_FLAG_NONE; - ChannelMemberFlags UserFlags = MEMBER_FLAG_NONE; + uint8 ChannelFlags = CHANNEL_FLAG_NONE; + uint8 UserFlags = MEMBER_FLAG_NONE; int32 ChannelID = 0; diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index a48639f1b03..9c6bb07f56e 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -498,3 +498,40 @@ WorldPacket const* WorldPackets::Character::SetFactionVisible::Write() _worldPacket << FactionIndex; return &_worldPacket; } + +WorldPackets::Character::CharCustomizeResponse::CharCustomizeResponse(WorldPackets::Character::CharCustomizeInfo const* info) + : ServerPacket(SMSG_CHAR_CUSTOMIZE, 16 + 1 + 1 + 1 + 1 + 1 + 1 + 1) +{ + CharGUID = info->CharGUID; + SexID = info->SexID; + SkinID = info->SkinID; + HairColorID = info->HairColorID; + HairStyleID = info->HairStyleID; + FacialHairStyleID = info->FacialHairStyleID; + FaceID = info->FaceID; + CharName = info->CharName; +} + +WorldPacket const* WorldPackets::Character::CharCustomizeResponse::Write() +{ + _worldPacket << CharGUID; + _worldPacket << uint8(SexID); + _worldPacket << uint8(SkinID); + _worldPacket << uint8(HairColorID); + _worldPacket << uint8(HairStyleID); + _worldPacket << uint8(FacialHairStyleID); + _worldPacket << uint8(FaceID); + _worldPacket.WriteBits(CharName.length(), 6); + _worldPacket.FlushBits(); + _worldPacket.WriteString(CharName); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Character::CharCustomizeFailed::Write() +{ + _worldPacket << uint8(Result); + _worldPacket << CharGUID; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/CharacterPackets.h b/src/server/game/Server/Packets/CharacterPackets.h index cee4f5edb5c..10f1053f8ee 100644 --- a/src/server/game/Server/Packets/CharacterPackets.h +++ b/src/server/game/Server/Packets/CharacterPackets.h @@ -608,7 +608,7 @@ namespace WorldPackets WorldPacket const* Write() override; - BarberShopResult Result; + BarberShopResult Result = BARBER_SHOP_RESULT_SUCCESS; }; class LogXPGain final : public ServerPacket @@ -686,6 +686,35 @@ namespace WorldPackets uint32 FactionIndex = 0; }; + + class CharCustomizeResponse final : public ServerPacket + { + public: + CharCustomizeResponse() : ServerPacket(SMSG_CHAR_CUSTOMIZE, 16 + 1 + 1 + 1 + 1 + 1 + 1 + 1) { } + CharCustomizeResponse(CharCustomizeInfo const* customizeInfo); + + WorldPacket const* Write() override; + + ObjectGuid CharGUID; + std::string CharName; + uint8 SexID = 0; + uint8 SkinID = 0; + uint8 HairColorID = 0; + uint8 HairStyleID = 0; + uint8 FacialHairStyleID = 0; + uint8 FaceID = 0; + }; + + class CharCustomizeFailed final : public ServerPacket + { + public: + CharCustomizeFailed() : ServerPacket(SMSG_CHAR_CUSTOMIZE_FAILED, 1 + 16) { } + + WorldPacket const* Write() override; + + uint8 Result = 0; + ObjectGuid CharGUID; + }; } } diff --git a/src/server/game/Server/Packets/ChatPackets.cpp b/src/server/game/Server/Packets/ChatPackets.cpp index 260770e65fe..4204278d514 100644 --- a/src/server/game/Server/Packets/ChatPackets.cpp +++ b/src/server/game/Server/Packets/ChatPackets.cpp @@ -92,7 +92,7 @@ void WorldPackets::Chat::ChatMessageEmote::Read() Text = _worldPacket.ReadString(len); } -void WorldPackets::Chat::Chat::Initalize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, +void WorldPackets::Chat::Chat::Initialize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, uint32 achievementId /*= 0*/, std::string channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/, std::string addonPrefix /*= ""*/) { // Clear everything because same packet can be used multiple times @@ -233,3 +233,15 @@ WorldPacket const* WorldPackets::Chat::ChatServerMessage::Write() return &_worldPacket; } + +void WorldPackets::Chat::ChatRegisterAddonPrefixes::Read() +{ + int32 count; + _worldPacket >> count; + + for (int32 i = 0; i < count; ++i) + { + uint32 lenghts = _worldPacket.ReadBits(5); + Prefixes.push_back(_worldPacket.ReadString(lenghts)); + } +} diff --git a/src/server/game/Server/Packets/ChatPackets.h b/src/server/game/Server/Packets/ChatPackets.h index 5bc55952168..c8bb038ce19 100644 --- a/src/server/game/Server/Packets/ChatPackets.h +++ b/src/server/game/Server/Packets/ChatPackets.h @@ -151,7 +151,7 @@ namespace WorldPackets public: Chat() : ServerPacket(SMSG_CHAT, 100) { } - void Initalize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, uint32 achievementId = 0, std::string channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string addonPrefix = ""); + void Initialize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, uint32 achievementId = 0, std::string channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string addonPrefix = ""); WorldPacket const* Write() override; uint8 SlashCmd = 0; ///< @see enum ChatMsg @@ -250,6 +250,24 @@ namespace WorldPackets int32 MessageID = 0; std::string StringParam; }; + + class ChatRegisterAddonPrefixes final : public ClientPacket + { + public: + ChatRegisterAddonPrefixes(WorldPacket&& packet) : ClientPacket(CMSG_CHAT_REGISTER_ADDON_PREFIXES, std::move(packet)) { } + + void Read() override; + + std::vector<std::string> Prefixes; + }; + + class ChatUnregisterAllAddonPrefixes final : public ClientPacket + { + public: + ChatUnregisterAllAddonPrefixes(WorldPacket&& packet) : ClientPacket(CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES, std::move(packet)) { } + + void Read() override { } + }; } } diff --git a/src/server/game/Server/Packets/CombatLogPackets.cpp b/src/server/game/Server/Packets/CombatLogPackets.cpp index 0702ad63f05..6742e797c54 100644 --- a/src/server/game/Server/Packets/CombatLogPackets.cpp +++ b/src/server/game/Server/Packets/CombatLogPackets.cpp @@ -147,3 +147,40 @@ WorldPacket const* WorldPackets::CombatLog::SpellHealLog::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::CombatLog::SpellPeriodicAuraLog::Write() +{ + _worldPacket << TargetGUID; + _worldPacket << CasterGUID; + _worldPacket << SpellID; + + _worldPacket << uint32(Effects.size()); + + for (SpellLogEffect const& effect : Effects) + { + _worldPacket << effect.Effect; + _worldPacket << int32(effect.Amount); + _worldPacket << int32(effect.OverHealOrKill); + _worldPacket << int32(effect.SchoolMaskOrPower); + _worldPacket << int32(effect.AbsorbedOrAmplitude); + _worldPacket << int32(effect.Resisted); + + _worldPacket.WriteBit(effect.Crit); + _worldPacket.WriteBit(effect.Multistrike); + + if (_worldPacket.WriteBit(effect.DebugInfo.is_initialized())) + { + _worldPacket << float(effect.DebugInfo->CritRollMade); + _worldPacket << float(effect.DebugInfo->CritRollNeeded); + } + + _worldPacket.FlushBits(); + } + + _worldPacket.WriteBit(LogData.is_initialized()); + _worldPacket.FlushBits(); + if (LogData) + _worldPacket << *LogData; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/CombatLogPackets.h b/src/server/game/Server/Packets/CombatLogPackets.h index c74e8112698..a931166ef80 100644 --- a/src/server/game/Server/Packets/CombatLogPackets.h +++ b/src/server/game/Server/Packets/CombatLogPackets.h @@ -91,7 +91,6 @@ namespace WorldPackets class SpellHealLog final : public ServerPacket { public: - SpellHealLog() : ServerPacket(SMSG_SPELL_HEAL_LOG, 16 + 16 + 4 * 4 + 1) { } WorldPacket const* Write() override; @@ -108,6 +107,39 @@ namespace WorldPackets Optional<float> CritRollNeeded; Optional<Spells::SpellCastLogData> LogData; /// @todo: find the correct way where to use it, in sniff always false }; + + class SpellPeriodicAuraLog final : public ServerPacket + { + public: + struct PeriodicalAuraLogEffectDebugInfo + { + float CritRollMade = 0.0f; + float CritRollNeeded = 0.0f; + }; + + struct SpellLogEffect + { + int32 Effect = 0; + int32 Amount = 0; + int32 OverHealOrKill = 0; + int32 SchoolMaskOrPower = 0; + int32 AbsorbedOrAmplitude = 0; + int32 Resisted = 0; + bool Crit = false; + bool Multistrike = false; + Optional<PeriodicalAuraLogEffectDebugInfo> DebugInfo; + }; + + SpellPeriodicAuraLog() : ServerPacket(SMSG_SPELL_PERIODIC_AURA_LOG, 16 + 16 + 4 + 4 + 1) { } + + WorldPacket const* Write() override; + + ObjectGuid TargetGUID; + ObjectGuid CasterGUID; + int32 SpellID = 0; + std::vector<SpellLogEffect> Effects; + Optional<Spells::SpellCastLogData> LogData; /// @todo: find the correct way where to use it, in sniff always false + }; } } diff --git a/src/server/game/Server/Packets/GarrisonPackets.cpp b/src/server/game/Server/Packets/GarrisonPackets.cpp index 456149bbdbb..88374e7ce62 100644 --- a/src/server/game/Server/Packets/GarrisonPackets.cpp +++ b/src/server/game/Server/Packets/GarrisonPackets.cpp @@ -60,8 +60,8 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonFollowe data << uint32(follower.CurrentMissionID); data << uint32(follower.AbilityID.size()); data << uint32(follower.FollowerStatus); - for (uint32 abilityId : follower.AbilityID) - data << uint32(abilityId); + for (GarrAbilityEntry const* ability : follower.AbilityID) + data << uint32(ability->ID); return data; } diff --git a/src/server/game/Server/Packets/GarrisonPackets.h b/src/server/game/Server/Packets/GarrisonPackets.h index 5fc386ab72b..1bb04c7ba95 100644 --- a/src/server/game/Server/Packets/GarrisonPackets.h +++ b/src/server/game/Server/Packets/GarrisonPackets.h @@ -22,6 +22,7 @@ #include "ObjectGuid.h" #include "Position.h" #include "PacketUtilities.h" +#include "DB2Structure.h" namespace WorldPackets { @@ -74,7 +75,7 @@ namespace WorldPackets uint32 Xp = 0; uint32 CurrentBuildingID = 0; uint32 CurrentMissionID = 0; - std::list<uint32> AbilityID; + std::list<GarrAbilityEntry const*> AbilityID; uint32 FollowerStatus; }; diff --git a/src/server/game/Server/Packets/InstancePackets.cpp b/src/server/game/Server/Packets/InstancePackets.cpp index 50b2a66a8b8..db5bdcbd9e8 100644 --- a/src/server/game/Server/Packets/InstancePackets.cpp +++ b/src/server/game/Server/Packets/InstancePackets.cpp @@ -30,3 +30,29 @@ WorldPacket const* WorldPackets::Instance::UpdateInstanceOwnership::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::Instance::InstanceInfo::Write() +{ + _worldPacket << int32(LockList.size()); + + for (InstanceLockInfos const& lockInfos : LockList) + _worldPacket << lockInfos; + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Instance::InstanceLockInfos const& lockInfos) +{ + data << lockInfos.MapID; + data << lockInfos.DifficultyID; + data << lockInfos.InstanceID; + data << lockInfos.TimeRemaining; + data << lockInfos.CompletedMask; + + data.WriteBit(lockInfos.Locked); + data.WriteBit(lockInfos.Extended); + + data.FlushBits(); + + return data; +} diff --git a/src/server/game/Server/Packets/InstancePackets.h b/src/server/game/Server/Packets/InstancePackets.h index 09f6c1efdcb..e38bcb97462 100644 --- a/src/server/game/Server/Packets/InstancePackets.h +++ b/src/server/game/Server/Packets/InstancePackets.h @@ -46,7 +46,31 @@ namespace WorldPackets int32 IOwnInstance = 0; // Used to control whether "Reset all instances" button appears on the UI - Script_CanShowResetInstances() // but it has been deperecated in favor of simply checking group leader, being inside an instance or using dungeon finder }; + + struct InstanceLockInfos + { + uint64 InstanceID = 0u; + uint32 MapID = 0u; + uint32 DifficultyID = 0u; + int32 TimeRemaining = 0; + uint32 CompletedMask = 0u; + + bool Locked = false; + bool Extended = false; + }; + + class InstanceInfo final : public ServerPacket + { + public: + InstanceInfo() : ServerPacket(SMSG_INSTANCE_INFO, 4) { } + + WorldPacket const* Write() override; + + std::vector<InstanceLockInfos> LockList; + }; } } +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Instance::InstanceLockInfos const& lockInfos); + #endif // InstancePackets_h__ diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index a4da605ca08..8b0bec535b3 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -374,3 +374,21 @@ void WorldPackets::Item::CancelTempEnchantment::Read() { _worldPacket >> Slot; } + +WorldPacket const* WorldPackets::Item::ItemCooldown::Write() +{ + _worldPacket << ItemGuid; + _worldPacket << uint32(SpellID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Item::ItemEnchantTimeUpdate::Write() +{ + _worldPacket << ItemGuid; + _worldPacket << uint32(DurationLeft); + _worldPacket << uint32(Slot); + _worldPacket << OwnerGuid; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/ItemPackets.h b/src/server/game/Server/Packets/ItemPackets.h index 7b0b9e41e4b..e73f42bcaf2 100644 --- a/src/server/game/Server/Packets/ItemPackets.h +++ b/src/server/game/Server/Packets/ItemPackets.h @@ -363,6 +363,30 @@ namespace WorldPackets int32 Slot = 0; }; + class ItemCooldown final : public ServerPacket + { + public: + ItemCooldown() : ServerPacket(SMSG_ITEM_COOLDOWN, 20) { } + + WorldPacket const* Write() override; + + ObjectGuid ItemGuid; + uint32 SpellID = 0; + }; + + class ItemEnchantTimeUpdate final : public ServerPacket + { + public: + ItemEnchantTimeUpdate() : ServerPacket(SMSG_ITEM_ENCHANT_TIME_UPDATE, 40) { } + + WorldPacket const* Write() override; + + ObjectGuid OwnerGuid; + ObjectGuid ItemGuid; + uint32 DurationLeft = 0; + uint32 Slot = 0; + }; + ByteBuffer& operator>>(ByteBuffer& data, InvUpdate& invUpdate); } } diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index a12ff537050..bbd3fcb2ba7 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -451,3 +451,72 @@ WorldPacket const* WorldPackets::Misc::Dismount::Write() return &_worldPacket; } + +void WorldPackets::Misc::SaveCUFProfiles::Read() +{ + uint32 count; + _worldPacket >> count; + + for (uint8 i = 0; i < count && i < MAX_CUF_PROFILES; i++) + { + std::unique_ptr<CUFProfile> cufProfile = Trinity::make_unique<CUFProfile>(); + + uint8 strLen = _worldPacket.ReadBits(7); + + // Bool Options + for (uint8 option = 0; option < CUF_BOOL_OPTIONS_COUNT; option++) + cufProfile->BoolOptions.set(option, _worldPacket.ReadBit()); + + // Other Options + _worldPacket >> cufProfile->FrameHeight; + _worldPacket >> cufProfile->FrameWidth; + + _worldPacket >> cufProfile->SortBy; + _worldPacket >> cufProfile->HealthText; + + _worldPacket >> cufProfile->TopPoint; + _worldPacket >> cufProfile->BottomPoint; + _worldPacket >> cufProfile->LeftPoint; + + _worldPacket >> cufProfile->TopOffset; + _worldPacket >> cufProfile->BottomOffset; + _worldPacket >> cufProfile->LeftOffset; + + cufProfile->ProfileName = _worldPacket.ReadString(strLen); + + CUFProfiles.push_back(std::move(cufProfile)); + } +} + +WorldPacket const* WorldPackets::Misc::LoadCUFProfiles::Write() +{ + _worldPacket << uint32(CUFProfiles.size()); + + for (CUFProfile const* cufProfile : CUFProfiles) + { + _worldPacket.WriteBits(cufProfile->ProfileName.size(), 7); + + // Bool Options + for (uint8 option = 0; option < CUF_BOOL_OPTIONS_COUNT; option++) + _worldPacket.WriteBit(cufProfile->BoolOptions[option]); + + // Other Options + _worldPacket << cufProfile->FrameHeight; + _worldPacket << cufProfile->FrameWidth; + + _worldPacket << cufProfile->SortBy; + _worldPacket << cufProfile->HealthText; + + _worldPacket << cufProfile->TopPoint; + _worldPacket << cufProfile->BottomPoint; + _worldPacket << cufProfile->LeftPoint; + + _worldPacket << cufProfile->TopOffset; + _worldPacket << cufProfile->BottomOffset; + _worldPacket << cufProfile->LeftOffset; + + _worldPacket.WriteString(cufProfile->ProfileName); + } + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index fda0e44990e..93bac0d208b 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -24,6 +24,7 @@ #include "G3D/Vector3.h" #include "Object.h" #include "Unit.h" +#include "Player.h" #include "Weather.h" namespace WorldPackets @@ -642,6 +643,26 @@ namespace WorldPackets ObjectGuid Guid; }; + + class SaveCUFProfiles final : public ClientPacket + { + public: + SaveCUFProfiles(WorldPacket&& packet) : ClientPacket(CMSG_SAVE_CUF_PROFILES, std::move(packet)) { } + + void Read() override; + + std::vector<std::unique_ptr<CUFProfile>> CUFProfiles; + }; + + class LoadCUFProfiles final : public ServerPacket + { + public: + LoadCUFProfiles() : ServerPacket(SMSG_LOAD_CUF_PROFILES, 20) { } + + WorldPacket const* Write() override; + + std::vector<CUFProfile const*> CUFProfiles; + }; } } diff --git a/src/server/game/Server/Packets/MovementPackets.h b/src/server/game/Server/Packets/MovementPackets.h index 6803bdf3b95..d4fb41cf330 100644 --- a/src/server/game/Server/Packets/MovementPackets.h +++ b/src/server/game/Server/Packets/MovementPackets.h @@ -398,7 +398,7 @@ namespace WorldPackets void Read() override; ObjectGuid MoverGUID; - uint32 TimeSkipped; + uint32 TimeSkipped = 0; }; } diff --git a/src/server/game/Server/Packets/PartyPackets.cpp b/src/server/game/Server/Packets/PartyPackets.cpp new file mode 100644 index 00000000000..f5cbfd7f5c2 --- /dev/null +++ b/src/server/game/Server/Packets/PartyPackets.cpp @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2008-2015 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 "PartyPackets.h" + +#include "Player.h" +#include "Pet.h" +#include "Vehicle.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "ObjectMgr.h" + +WorldPacket const* WorldPackets::Party::PartyCommandResult::Write() +{ + _worldPacket.WriteBits(Name.size(), 9); + + _worldPacket.WriteBits(Command, 4); + _worldPacket.WriteBits(Result, 6); + + _worldPacket << ResultData; + _worldPacket << ResultGUID; + _worldPacket.WriteString(Name); + + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +void WorldPackets::Party::PartyInviteClient::Read() +{ + uint32 targetNameLen, targetRealmLen; + + _worldPacket >> PartyIndex; + _worldPacket >> ProposedRoles; + _worldPacket >> TargetGUID; + _worldPacket >> TargetCfgRealmID; + + targetNameLen = _worldPacket.ReadBits(9); + targetRealmLen = _worldPacket.ReadBits(9); + + TargetName = _worldPacket.ReadString(targetNameLen); + TargetRealm = _worldPacket.ReadString(targetRealmLen); +} + +WorldPacket const* WorldPackets::Party::PartyInvite::Write() +{ + // Order guessed + _worldPacket.WriteBit(CanAccept); + _worldPacket.WriteBit(MightCRZYou); + _worldPacket.WriteBit(MustBeBNetFriend); + _worldPacket.WriteBit(AllowMultipleRoles); + _worldPacket.WriteBit(IsXRealm); + + _worldPacket.WriteBits(InviterName.size(), 6); + + _worldPacket << InviterGUID; + _worldPacket << InviterBNetAccountId; + + _worldPacket << InviterVirtualRealmAddress; + _worldPacket << Unk1; + + _worldPacket.WriteBit(IsLocal); + _worldPacket.WriteBit(Unk2); + + _worldPacket.WriteBits(InviterRealmNameActual.size(), 8); + _worldPacket.WriteBits(InviterRealmNameNormalized.size(), 8); + _worldPacket.WriteString(InviterRealmNameActual); + _worldPacket.WriteString(InviterRealmNameNormalized); + + _worldPacket << ProposedRoles; + _worldPacket << int32(LfgSlots.size()); + _worldPacket << LfgCompletedMask; + + _worldPacket.WriteString(InviterName); + + for (int32 LfgSlot : LfgSlots) + _worldPacket << LfgSlot; + + return &_worldPacket; +} + +void WorldPackets::Party::PartyInvite::Initialize(Player* const inviter, int32 proposedRoles, bool canAccept) +{ + CanAccept = canAccept; + + InviterName = inviter->GetName(); + InviterGUID = inviter->GetGUID(); + InviterBNetAccountId = inviter->GetSession()->GetAccountGUID(); + + ProposedRoles = proposedRoles; + + std::string realmName = sObjectMgr->GetRealmName(realmHandle.Index); + + InviterVirtualRealmAddress = GetVirtualRealmAddress(); + InviterRealmNameActual = realmName; + InviterRealmNameNormalized = realmName; +} + +void WorldPackets::Party::PartyInviteResponse::Read() +{ + _worldPacket >> PartyIndex; + + Accept = _worldPacket.ReadBit(); + + bool hasRolesDesired = _worldPacket.ReadBit(); + if (hasRolesDesired) + { + RolesDesired = boost::in_place(); + _worldPacket >> *RolesDesired; + } +} + +void WorldPackets::Party::PartyUninvite::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> TargetGUID; + + uint8 reasonLen = _worldPacket.ReadBits(8); + Reason = _worldPacket.ReadString(reasonLen); +} + +WorldPacket const* WorldPackets::Party::GroupDecline::Write() +{ + _worldPacket.WriteBits(Name.length(), 9); + _worldPacket.FlushBits(); + _worldPacket.WriteString(Name); + + return &_worldPacket; +} + +void WorldPackets::Party::RequestPartyMemberStats::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> TargetGUID; +} + +WorldPacket const* WorldPackets::Party::PartyMemberStats::Write() +{ + _worldPacket.WriteBit(ForEnemy); + + _worldPacket << MemberStats; + + return &_worldPacket; +} + +void WorldPackets::Party::SetPartyLeader::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> TargetGUID; +} + +void WorldPackets::Party::SetRole::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> TargetGUID; + _worldPacket >> Role; +} + +WorldPacket const* WorldPackets::Party::RoleChangedInform::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << From; + _worldPacket << ChangedUnit; + _worldPacket << OldRole; + _worldPacket << NewRole; + + return &_worldPacket; +} + +void WorldPackets::Party::LeaveGroup::Read() +{ + _worldPacket >> PartyIndex; +} + +void WorldPackets::Party::SetLootMethod::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> LootMethod; + _worldPacket >> LootMasterGUID; + _worldPacket >> LootThreshold; +} + +void WorldPackets::Party::MinimapPingClient::Read() +{ + _worldPacket >> PositionX; + _worldPacket >> PositionY; + _worldPacket >> PartyIndex; +} + +WorldPacket const* WorldPackets::Party::MinimapPing::Write() +{ + _worldPacket << Sender; + _worldPacket << PositionX; + _worldPacket << PositionY; + + return &_worldPacket; +} + +void WorldPackets::Party::UpdateRaidTarget::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> Target; + _worldPacket >> Symbol; +} + +WorldPacket const* WorldPackets::Party::SendRaidTargetUpdateSingle::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << Symbol; + _worldPacket << Target; + _worldPacket << ChangedBy; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Party::SendRaidTargetUpdateAll::Write() +{ + _worldPacket << PartyIndex; + + _worldPacket << int32(TargetIcons.size()); + + std::map<uint8, ObjectGuid>::const_iterator itr; + for (itr = TargetIcons.begin(); itr != TargetIcons.end(); itr++) + { + _worldPacket << itr->second; + _worldPacket << itr->first; + } + + return &_worldPacket; +} + +void WorldPackets::Party::ConvertRaid::Read() +{ + Raid = _worldPacket.ReadBit(); +} + +void WorldPackets::Party::RequestPartyJoinUpdates::Read() +{ + _worldPacket >> PartyIndex; +} + +void WorldPackets::Party::SetAssistantLeader::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> Target; + Apply = _worldPacket.ReadBit(); +} + +void WorldPackets::Party::DoReadyCheck::Read() +{ + _worldPacket >> PartyIndex; +} + +WorldPacket const* WorldPackets::Party::ReadyCheckStarted::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << PartyGUID; + _worldPacket << InitiatorGUID; + _worldPacket << Duration; + + return &_worldPacket; +} + +void WorldPackets::Party::ReadyCheckResponseClient::Read() +{ + _worldPacket >> PartyIndex; + IsReady = _worldPacket.ReadBit(); +} + +WorldPacket const* WorldPackets::Party::ReadyCheckResponse::Write() +{ + _worldPacket << PartyGUID; + _worldPacket << Player; + + _worldPacket.WriteBit(IsReady); + + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Party::ReadyCheckCompleted::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << PartyGUID; + + return &_worldPacket; +} + +void WorldPackets::Party::OptOutOfLoot::Read() +{ + PassOnLoot = _worldPacket.ReadBit(); +} + +void WorldPackets::Party::InitiateRolePoll::Read() +{ + _worldPacket >> PartyIndex; +} + +WorldPacket const* WorldPackets::Party::RolePollInform::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << From; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Party::GroupNewLeader::Write() +{ + _worldPacket << PartyIndex; + _worldPacket.WriteBits(Name.size(), 6); + _worldPacket.WriteString(Name); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Party::PartyUpdate::Write() +{ + _worldPacket << PartyType; + _worldPacket << PartyIndex; + _worldPacket << PartyFlags; + + _worldPacket << MyIndex; + _worldPacket << PartyGUID; + _worldPacket << SequenceNum; + _worldPacket << LeaderGUID; + + _worldPacket << PlayerList; + + _worldPacket.WriteBit(LfgInfos.is_initialized()); + _worldPacket.WriteBit(LootSettings.is_initialized()); + _worldPacket.WriteBit(DifficultySettings.is_initialized()); + + _worldPacket.FlushBits(); + + if (LfgInfos.is_initialized()) + _worldPacket << *LfgInfos; + + if (LootSettings.is_initialized()) + _worldPacket << *LootSettings; + + if (DifficultySettings.is_initialized()) + _worldPacket << *DifficultySettings; + + return &_worldPacket; +} + +void WorldPackets::Party::SetEveryoneIsAssistant::Read() +{ + _worldPacket >> PartyIndex; + EveryoneIsAssistant = _worldPacket.ReadBit(); +} + +void WorldPackets::Party::ChangeSubGroup::Read() +{ + _worldPacket >> TargetGUID; + _worldPacket >> PartyIndex; + _worldPacket >> NewSubGroup; +} + +void WorldPackets::Party::SwapSubGroups::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> FirstTarget; + _worldPacket >> SecondTarget; +} + +void WorldPackets::Party::ClearRaidMarker::Read() +{ + _worldPacket >> MarkerId; +} + +WorldPacket const* WorldPackets::Party::RaidMarkersChanged::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << ActiveMarkers; + + _worldPacket.WriteBits(RaidMarkers.size(), 4); + _worldPacket.FlushBits(); + + for (RaidMarker* raidMarker : RaidMarkers) + { + _worldPacket << raidMarker->TransportGUID; + _worldPacket << raidMarker->Location.GetMapId(); + _worldPacket << raidMarker->Location.PositionXYZStream(); + } + + return &_worldPacket; +} + +void WorldPackets::Party::PartyMemberStats::Initialize(Player const* player) +{ + ForEnemy = false; + + MemberStats.GUID = player->GetGUID(); + + // Status + MemberStats.Status = MEMBER_STATUS_ONLINE; + + if (player->IsPvP()) + MemberStats.Status |= MEMBER_STATUS_PVP; + + if (!player->IsAlive()) + { + if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + MemberStats.Status |= MEMBER_STATUS_GHOST; + else + MemberStats.Status |= MEMBER_STATUS_DEAD; + } + + if (player->IsFFAPvP()) + MemberStats.Status |= MEMBER_STATUS_PVP_FFA; + + if (player->isAFK()) + MemberStats.Status |= MEMBER_STATUS_AFK; + + if (player->isDND()) + MemberStats.Status |= MEMBER_STATUS_DND; + + // Level + MemberStats.Level = player->getLevel(); + + // Health + MemberStats.CurrentHealth = player->GetHealth(); + MemberStats.MaxHealth = player->GetMaxHealth(); + + // Power + MemberStats.PowerType = player->getPowerType(); + MemberStats.CurrentPower = player->GetPower(player->getPowerType()); + MemberStats.MaxPower = player->GetMaxPower(player->getPowerType()); + + // Position + MemberStats.ZoneID = player->GetZoneId(); + MemberStats.PositionX = int16(player->GetPositionX()); + MemberStats.PositionY = int16(player->GetPositionY()); + MemberStats.PositionZ = int16(player->GetPositionZ()); + + // Unk + MemberStats.Unk322 = 0; // Always 0 + MemberStats.Unk704[0] = 1; // Always 1 + MemberStats.Unk704[1] = 0; // Always 0 + MemberStats.Unk200000 = 0; // Always 0 + + MemberStats.Unk2000000 = 0; + MemberStats.Unk4000000 = 0; + + // Vehicle + if (player->GetVehicle() && player->GetVehicle()->GetVehicleInfo()) + MemberStats.VehicleSeat = player->GetVehicle()->GetVehicleInfo()->SeatID[player->m_movementInfo.transport.seat]; + + // Auras + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (AuraApplication const* aurApp = player->GetVisibleAura(i)) + { + WorldPackets::Party::GroupAura aura; + + aura.SpellId = aurApp->GetBase()->GetId(); + aura.EffectMask = aurApp->GetEffectMask(); + aura.Scalings = aurApp->GetFlags(); // ?? + + if (aurApp->GetFlags() & AFLAG_SCALABLE) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + float scale = 0.f; + if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) + scale = float(eff->GetAmount()); + aura.EffectScales.push_back(scale); + } + } + + MemberStats.AuraList.push_back(aura); + } + } + + // Phases + std::set<uint32> const& phases = player->GetPhases(); + MemberStats.Phases.PhaseShiftFlags = 0x08 | (phases.size() ? 0x10 : 0); + MemberStats.Phases.PersonalGUID = ObjectGuid::Empty; + for (uint32 phaseId : phases) + { + WorldPackets::Party::GroupPhase phase; + phase.Id = phaseId; + phase.Flags = 1; + MemberStats.Phases.List.push_back(phase); + } + + // Pet + if (player->GetPet()) + { + Pet* pet = player->GetPet(); + + MemberStats.PetStats = boost::in_place(); + + MemberStats.PetStats->GUID = pet->GetGUID(); + MemberStats.PetStats->Name = pet->GetName(); + MemberStats.PetStats->ModelId = pet->GetDisplayId(); + + MemberStats.PetStats->CurrentHealth = pet->GetHealth(); + MemberStats.PetStats->MaxHealth = pet->GetMaxHealth(); + + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (AuraApplication const* aurApp = pet->GetVisibleAura(i)) + { + WorldPackets::Party::GroupAura aura; + + aura.SpellId = aurApp->GetBase()->GetId(); + aura.EffectMask = aurApp->GetEffectMask(); + aura.Scalings = aurApp->GetFlags(); // ?? + + if (aurApp->GetFlags() & AFLAG_SCALABLE) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + float scale = 0.f; + if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) + scale = float(eff->GetAmount()); + aura.EffectScales.push_back(scale); + } + } + + MemberStats.PetStats->AuraList.push_back(aura); + } + } + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPhase const& phase) +{ + data << phase.Flags; + data << phase.Id; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPhases const& phases) +{ + data << phases.PhaseShiftFlags; + data << int32(phases.List.size()); + data << phases.PersonalGUID; + + for (WorldPackets::Party::GroupPhase const& phase : phases.List) + data << phase; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupAura const& aura) +{ + data << aura.SpellId; + data << aura.Scalings; + data << aura.EffectMask; + + data << int32(aura.EffectScales.size()); + for (float scale : aura.EffectScales) + data << scale; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, std::vector<WorldPackets::Party::GroupAura> const& auraList) +{ + data << int32(auraList.size()); + for (WorldPackets::Party::GroupAura const& aura : auraList) + data << aura; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPetStats const& petStats) +{ + data << petStats.GUID; + + data << petStats.ModelId; + + data << petStats.CurrentHealth; + data << petStats.MaxHealth; + + data << petStats.AuraList; + + data.WriteBits(petStats.Name.size(), 8); + data.FlushBits(); + data.WriteString(petStats.Name); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupMemberStats const& memberStats) +{ + data << memberStats.GUID; + + for (uint8 i = 0; i < 2; i++) + data << memberStats.Unk704[i]; + + data << memberStats.Status; + + data << memberStats.PowerType; + + data << memberStats.Unk322; + + data << memberStats.CurrentHealth; + data << memberStats.MaxHealth; + + data << memberStats.CurrentPower; + data << memberStats.MaxPower; + + data << memberStats.Level; + + data << memberStats.Unk200000; + + data << memberStats.ZoneID; + + data << memberStats.Unk2000000; + data << memberStats.Unk4000000; + + data << memberStats.PositionX; + data << memberStats.PositionY; + data << memberStats.PositionZ; + + data << memberStats.VehicleSeat; + + data << int32(memberStats.AuraList.size()); + + data << memberStats.Phases; + + for (WorldPackets::Party::GroupAura const& aura : memberStats.AuraList) + data << aura; + + data.WriteBit(memberStats.PetStats.is_initialized()); + data.FlushBits(); + + if (memberStats.PetStats.is_initialized()) + data << *memberStats.PetStats; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, std::vector<WorldPackets::Party::GroupPlayerInfos> const& playerList) +{ + data << int32(playerList.size()); + + for (WorldPackets::Party::GroupPlayerInfos const& playerInfos : playerList) + data << playerInfos; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPlayerInfos const& playerInfos) +{ + data.WriteBits(playerInfos.Name.size(), 6); + data.FlushBits(); + + data << playerInfos.GUID; + data << playerInfos.Status; + data << playerInfos.Subgroup; + data << playerInfos.Flags; + data << playerInfos.RolesAssigned; + data << playerInfos.Class; + + data.WriteString(playerInfos.Name); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupLfgInfos const& lfgInfos) +{ + data << lfgInfos.MyFlags; + data << lfgInfos.Slot; + data << lfgInfos.MyRandomSlot; + data << lfgInfos.MyPartialClear; + data << lfgInfos.MyGearDiff; + data << lfgInfos.MyStrangerCount; + data << lfgInfos.MyKickVoteCount; + data << lfgInfos.BootCount; + + data.WriteBit(lfgInfos.Aborted); + data.WriteBit(lfgInfos.MyFirstReward); + data.FlushBits(); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupLootSettings const& lootSettings) +{ + data << lootSettings.Method; + data << lootSettings.LootMaster; + data << lootSettings.Threshold; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupDifficultySettings const& difficultySettings) +{ + data << difficultySettings.DungeonDifficultyID; + data << difficultySettings.RaidDifficultyID; + data << difficultySettings.LegacyRaidDifficultyID; + + return data; +} diff --git a/src/server/game/Server/Packets/PartyPackets.h b/src/server/game/Server/Packets/PartyPackets.h new file mode 100644 index 00000000000..ed3eed60ef4 --- /dev/null +++ b/src/server/game/Server/Packets/PartyPackets.h @@ -0,0 +1,616 @@ +/* + * Copyright (C) 2008-2015 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 PartyPackets_h__ +#define PartyPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" +#include "Group.h" + +namespace WorldPackets +{ + namespace Party + { + class PartyCommandResult final : public ServerPacket + { + public: + PartyCommandResult() : ServerPacket(SMSG_PARTY_COMMAND_RESULT, 23) { } + + WorldPacket const* Write() override; + + std::string Name; + uint8 Command = 0u; + uint8 Result = 0u; + uint32 ResultData = 0u; + ObjectGuid ResultGUID; + }; + + class PartyInviteClient final : public ClientPacket + { + public: + PartyInviteClient(WorldPacket&& packet) : ClientPacket(CMSG_PARTY_INVITE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + int32 ProposedRoles = 0; + int32 TargetCfgRealmID = 0; + std::string TargetName; + std::string TargetRealm; + ObjectGuid TargetGUID; + }; + + class PartyInvite final : public ServerPacket + { + public: + PartyInvite() : ServerPacket(SMSG_PARTY_INVITE, 55) { } + + WorldPacket const* Write() override; + void Initialize(Player* const inviter, int32 proposedRoles, bool canAccept); + + bool MightCRZYou = false; + bool MustBeBNetFriend = false; + bool AllowMultipleRoles = false; + bool Unk2 = false; + int16 Unk1 = 0; + + bool CanAccept = false; + + // Inviter + ObjectGuid InviterGUID; + ObjectGuid InviterBNetAccountId; + std::string InviterName; + + // Realm + bool IsXRealm = false; + bool IsLocal = true; + uint32 InviterVirtualRealmAddress = 0u; + std::string InviterRealmNameActual; + std::string InviterRealmNameNormalized; + + // Lfg + int32 ProposedRoles = 0; + int32 LfgCompletedMask = 0; + std::vector<int32> LfgSlots; + }; + + class PartyInviteResponse final : public ClientPacket + { + public: + PartyInviteResponse(WorldPacket&& packet) : ClientPacket(CMSG_PARTY_INVITE_RESPONSE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + bool Accept = false; + Optional<int32> RolesDesired; + }; + + class PartyUninvite final : public ClientPacket + { + public: + PartyUninvite(WorldPacket&& packet) : ClientPacket(CMSG_PARTY_UNINVITE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid TargetGUID; + std::string Reason; + }; + + class GroupDecline final : public ServerPacket + { + public: + GroupDecline(std::string const& name) : ServerPacket(SMSG_GROUP_DECLINE, 2 + name.size()), Name(name) { } + + WorldPacket const* Write() override; + + std::string Name; + }; + + class RequestPartyMemberStats final : public ClientPacket + { + public: + RequestPartyMemberStats(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_PARTY_MEMBER_STATS, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid TargetGUID; + }; + + struct GroupPhase + { + uint16 Flags = 0u; + uint16 Id = 0u; + }; + + struct GroupPhases + { + int32 PhaseShiftFlags = 0; + ObjectGuid PersonalGUID; + std::vector<GroupPhase> List; + }; + + struct GroupAura + { + uint32 SpellId = 0u; + uint8 Scalings = 0; + uint32 EffectMask = 0u; + std::vector<float> EffectScales; + }; + + struct GroupPetStats + { + ObjectGuid GUID; + std::string Name; + int16 ModelId = 0; + + int32 CurrentHealth = 0; + int32 MaxHealth = 0; + + std::vector<GroupAura> AuraList; + }; + + struct GroupMemberStats + { + ObjectGuid GUID; + int16 Level = 0; + int16 Status = 0; + + int32 CurrentHealth = 0; + int32 MaxHealth; + + uint8 PowerType = 0u; + int16 CurrentPower = 0; + int16 MaxPower = 0; + + int16 ZoneID = 0; + int16 PositionX = 0; + int16 PositionY = 0; + int16 PositionZ = 0; + + int32 VehicleSeat = 0; + + GroupPhases Phases; + std::vector<GroupAura> AuraList; + Optional<GroupPetStats> PetStats; + + int16 Unk322 = 0; + int16 Unk200000 = 0; + int16 Unk2000000 = 0; + int32 Unk4000000 = 0; + int8 Unk704[2]; + }; + + class PartyMemberStats final : public ServerPacket + { + public: + PartyMemberStats() : ServerPacket(SMSG_PARTY_MEMBER_STATE, 80) { } + + WorldPacket const* Write() override; + void Initialize(Player const* player); + + GroupMemberStats MemberStats; + bool ForEnemy = false; + }; + + class SetPartyLeader final : public ClientPacket + { + public: + SetPartyLeader(WorldPacket&& packet) : ClientPacket(CMSG_SET_PARTY_LEADER, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid TargetGUID; + }; + + class SetRole final : public ClientPacket + { + public: + SetRole(WorldPacket&& packet) : ClientPacket(CMSG_SET_ROLE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid TargetGUID; + int32 Role = 0; + }; + + class RoleChangedInform final : public ServerPacket + { + public: + RoleChangedInform() : ServerPacket(SMSG_ROLE_CHANGED_INFORM, 41) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid From; + ObjectGuid ChangedUnit; + int32 OldRole = 0; + int32 NewRole = 0; + }; + + class LeaveGroup final : public ClientPacket + { + public: + LeaveGroup(WorldPacket&& packet) : ClientPacket(CMSG_LEAVE_GROUP, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + }; + + class SetLootMethod final : public ClientPacket + { + public: + SetLootMethod(WorldPacket&& packet) : ClientPacket(CMSG_SET_LOOT_METHOD, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid LootMasterGUID; + uint8 LootMethod = 0u; + uint32 LootThreshold = 0u; + }; + + class MinimapPingClient final : public ClientPacket + { + public: + MinimapPingClient(WorldPacket&& packet) : ClientPacket(CMSG_MINIMAP_PING, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + float PositionX = 0.f; + float PositionY = 0.f; + }; + + class MinimapPing final : public ServerPacket + { + public: + MinimapPing() : ServerPacket(SMSG_MINIMAP_PING, 24) { } + + WorldPacket const* Write() override; + + ObjectGuid Sender; + float PositionX = 0.f; + float PositionY = 0.f; + }; + + class UpdateRaidTarget final : public ClientPacket + { + public: + UpdateRaidTarget(WorldPacket&& packet) : ClientPacket(CMSG_UPDATE_RAID_TARGET, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid Target; + int8 Symbol = 0; + }; + + class SendRaidTargetUpdateSingle final : public ServerPacket + { + public: + SendRaidTargetUpdateSingle() : ServerPacket(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, 34) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid Target; + ObjectGuid ChangedBy; + int8 Symbol = 0; + }; + + class SendRaidTargetUpdateAll final : public ServerPacket + { + public: + SendRaidTargetUpdateAll() : ServerPacket(SMSG_SEND_RAID_TARGET_UPDATE_ALL, 1 + TARGET_ICONS_COUNT * (1 + 16)) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + std::map<uint8, ObjectGuid> TargetIcons; + }; + + class ConvertRaid final : public ClientPacket + { + public: + ConvertRaid(WorldPacket&& packet) : ClientPacket(CMSG_CONVERT_RAID, std::move(packet)) { } + + void Read() override; + + bool Raid = false; + }; + + class RequestPartyJoinUpdates final : public ClientPacket + { + public: + RequestPartyJoinUpdates(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_PARTY_JOIN_UPDATES, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + }; + + class SetAssistantLeader final : public ClientPacket + { + public: + SetAssistantLeader(WorldPacket&& packet) : ClientPacket(CMSG_SET_ASSISTANT_LEADER, std::move(packet)) { } + + void Read() override; + + ObjectGuid Target; + int8 PartyIndex = 0; + bool Apply = false; + }; + + class DoReadyCheck final : public ClientPacket + { + public: + DoReadyCheck(WorldPacket&& packet) : ClientPacket(CMSG_DO_READY_CHECK, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + }; + + class ReadyCheckStarted final : public ServerPacket + { + public: + ReadyCheckStarted() : ServerPacket(SMSG_READY_CHECK_STARTED, 37) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid PartyGUID; + ObjectGuid InitiatorGUID; + uint32 Duration = 0u; + }; + + class ReadyCheckResponseClient final : public ClientPacket + { + public: + ReadyCheckResponseClient(WorldPacket&& packet) : ClientPacket(CMSG_READY_CHECK_RESPONSE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + bool IsReady = false; + }; + + class ReadyCheckResponse final : public ServerPacket + { + public: + ReadyCheckResponse() : ServerPacket(SMSG_READY_CHECK_RESPONSE, 19) { } + + WorldPacket const* Write() override; + + ObjectGuid PartyGUID; + ObjectGuid Player; + bool IsReady = false; + }; + + class ReadyCheckCompleted final : public ServerPacket + { + public: + ReadyCheckCompleted() : ServerPacket(SMSG_READY_CHECK_COMPLETED, 17) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid PartyGUID; + }; + + class RequestRaidInfo final : public ClientPacket + { + public: + RequestRaidInfo(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_RAID_INFO, std::move(packet)) { } + + void Read() override { } + }; + + class OptOutOfLoot final : public ClientPacket + { + public: + OptOutOfLoot(WorldPacket&& packet) : ClientPacket(CMSG_OPT_OUT_OF_LOOT, std::move(packet)) { } + + void Read() override; + + bool PassOnLoot = false; + }; + + class InitiateRolePoll final : public ClientPacket + { + public: + InitiateRolePoll(WorldPacket&& packet) : ClientPacket(CMSG_INITIATE_ROLE_POLL, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + }; + + class RolePollInform final : public ServerPacket + { + public: + RolePollInform() : ServerPacket(SMSG_ROLE_POLL_INFORM, 17) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid From; + }; + + class GroupNewLeader final : public ServerPacket + { + public: + GroupNewLeader() : ServerPacket(SMSG_GROUP_NEW_LEADER, 14) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + std::string Name; + }; + + struct GroupPlayerInfos + { + ObjectGuid GUID; + std::string Name; + uint8 Class = 0; + + uint8 Status = 0u; + uint8 Subgroup = 0u; + uint8 Flags = 0u; + uint8 RolesAssigned = 0u; + }; + + struct GroupLfgInfos + { + int32 Slot = 0u; + int8 BootCount = 0; + + bool Aborted = false; + + int32 MyRandomSlot = 0; + uint8 MyFlags = 0u; + uint8 MyPartialClear = 0u; + float MyGearDiff = 0.f; + + int8 MyStrangerCount = 0; + int8 MyKickVoteCount = 0; + + bool MyFirstReward = false; + }; + + struct GroupLootSettings + { + uint8 Method = 0u; + ObjectGuid LootMaster; + uint8 Threshold = 0u; + }; + + struct GroupDifficultySettings + { + uint32 DungeonDifficultyID = 0u; + uint32 RaidDifficultyID = 0u; + uint32 LegacyRaidDifficultyID = 0u; + }; + + class PartyUpdate final : public ServerPacket + { + public: + PartyUpdate() : ServerPacket(SMSG_PARTY_UPDATE, 200) { } + + WorldPacket const* Write() override; + + int8 PartyFlags = 0; + int8 PartyIndex = 0; + int8 PartyType = 0; + + ObjectGuid PartyGUID; + ObjectGuid LeaderGUID; + + int32 MyIndex = 0; + int32 SequenceNum = 0; + + std::vector<GroupPlayerInfos> PlayerList; + + Optional<GroupLfgInfos> LfgInfos; + Optional<GroupLootSettings> LootSettings; + Optional<GroupDifficultySettings> DifficultySettings; + }; + + class SetEveryoneIsAssistant final : public ClientPacket + { + public: + SetEveryoneIsAssistant(WorldPacket&& packet) : ClientPacket(CMSG_SET_EVERYONE_IS_ASSISTANT, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + bool EveryoneIsAssistant = false; + }; + + class ChangeSubGroup final : public ClientPacket + { + public: + ChangeSubGroup(WorldPacket&& packet) : ClientPacket(CMSG_CHANGE_SUB_GROUP, std::move(packet)) { } + + void Read() override; + + ObjectGuid TargetGUID; + int8 PartyIndex = 0; + uint8 NewSubGroup = 0u; + }; + + class SwapSubGroups final : public ClientPacket + { + public: + SwapSubGroups(WorldPacket&& packet) : ClientPacket(CMSG_SWAP_SUB_GROUPS, std::move(packet)) { } + + void Read() override; + + ObjectGuid FirstTarget; + ObjectGuid SecondTarget; + int8 PartyIndex = 0; + }; + + class ClearRaidMarker final : public ClientPacket + { + public: + ClearRaidMarker(WorldPacket&& packet) : ClientPacket(CMSG_CLEAR_RAID_MARKER, std::move(packet)) { } + + void Read() override; + + uint8 MarkerId = 0u; + }; + + class RaidMarkersChanged final : public ServerPacket + { + public: + RaidMarkersChanged() : ServerPacket(SMSG_RAID_MARKERS_CHANGED, 6) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + uint32 ActiveMarkers = 0u; + + std::vector<RaidMarker*> RaidMarkers; + }; + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPhase const& phase); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPhases const& phases); + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupAura const& aura); +ByteBuffer& operator<<(ByteBuffer& data, std::vector<WorldPackets::Party::GroupAura> const& auraList); + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPetStats const& petStats); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupMemberStats const& memberStats); + +ByteBuffer& operator<<(ByteBuffer& data, std::vector<WorldPackets::Party::GroupPlayerInfos> const& playerList); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPlayerInfos const& playerInfos); + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupLfgInfos const& lfgInfos); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupLootSettings const& lootSettings); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupDifficultySettings const& difficultySettings); + +#endif // PartyPackets_h__ diff --git a/src/server/game/Server/Packets/QuestPackets.cpp b/src/server/game/Server/Packets/QuestPackets.cpp index ad4001899fe..d792783cf9a 100644 --- a/src/server/game/Server/Packets/QuestPackets.cpp +++ b/src/server/game/Server/Packets/QuestPackets.cpp @@ -72,7 +72,7 @@ WorldPacket const* WorldPackets::Quest::QueryQuestInfoResponse::Write() _worldPacket << Info.SuggestedGroupNum; _worldPacket << Info.RewardNextQuest; _worldPacket << Info.RewardXPDifficulty; - _worldPacket << Info.Float10; // Unk + _worldPacket << Info.RewardXPMultiplier; _worldPacket << Info.RewardMoney; _worldPacket << Info.RewardMoneyDifficulty; _worldPacket << Info.Float13; // Unk diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h index a83bcc219be..b2d7269ebb0 100644 --- a/src/server/game/Server/Packets/QuestPackets.h +++ b/src/server/game/Server/Packets/QuestPackets.h @@ -116,6 +116,7 @@ namespace WorldPackets int32 SuggestedGroupNum = 0; int32 RewardNextQuest = 0; // client will request this quest from NPC, if not 0 int32 RewardXPDifficulty = 0; // used for calculating rewarded experience + float RewardXPMultiplier = 1.0f; int32 RewardMoney = 0; // reward money (below max lvl) int32 RewardMoneyDifficulty = 0; // used in XP calculation at client int32 RewardBonusMoney = 0; @@ -163,8 +164,6 @@ namespace WorldPackets int32 RewardCurrencyID[QUEST_REWARD_CURRENCY_COUNT] = {}; int32 RewardCurrencyQty[QUEST_REWARD_CURRENCY_COUNT] = {}; - // Non JAM data - float Float10 = 1.0f; float Float13 = 1.0f; int32 AllowableRaces = -1; }; diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 4c87e00fc91..70a22f0b1bb 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -33,6 +33,7 @@ #include "Packets/GameObjectPackets.h" #include "Packets/GarrisonPackets.h" #include "Packets/GuildPackets.h" +#include "Packets/PartyPackets.h" #include "Packets/InspectPackets.h" #include "Packets/InstancePackets.h" #include "Packets/ItemPackets.h" @@ -259,7 +260,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_CHALLENGE_MODE_REQUEST_MAP_STATS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CHANGE_BAG_SLOT_FLAG, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CHANGE_MONUMENT_APPEARANCE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANGE_SUB_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupChangeSubGroupOpcode ); + DEFINE_HANDLER(CMSG_CHANGE_SUB_GROUP, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::ChangeSubGroup, &WorldSession::HandleChangeSubGroupOpcode); DEFINE_HANDLER(CMSG_CHARACTER_RENAME_REQUEST, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CharacterRenameRequest, &WorldSession::HandleCharRenameOpcode); DEFINE_HANDLER(CMSG_CHAR_CUSTOMIZE, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CharCustomize, &WorldSession::HandleCharCustomizeOpcode); DEFINE_HANDLER(CMSG_CHAR_DELETE, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CharDelete, &WorldSession::HandleCharDeleteOpcode); @@ -308,14 +309,14 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_CHAT_MESSAGE_SAY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); DEFINE_HANDLER(CMSG_CHAT_MESSAGE_WHISPER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessageWhisper, &WorldSession::HandleChatMessageWhisperOpcode); DEFINE_HANDLER(CMSG_CHAT_MESSAGE_YELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAT_REGISTER_ADDON_PREFIXES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonRegisteredPrefixesOpcode); + DEFINE_HANDLER(CMSG_CHAT_REGISTER_ADDON_PREFIXES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatRegisterAddonPrefixes, &WorldSession::HandleAddonRegisteredPrefixesOpcode); DEFINE_HANDLER(CMSG_CHAT_REPORT_FILTERED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAT_REPORT_IGNORED, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChatIgnoredOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnregisterAddonPrefixesOpcode); + DEFINE_HANDLER(CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatUnregisterAllAddonPrefixes, &WorldSession::HandleUnregisterAllAddonPrefixesOpcode); DEFINE_HANDLER(CMSG_CHECK_RAF_EMAIL_ENABLED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CHECK_WOW_TOKEN_VETERAN_ELIGIBILITY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CHOICE_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_CLEAR_RAID_MARKER, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_CLEAR_RAID_MARKER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::ClearRaidMarker, &WorldSession::HandleClearRaidMarker); DEFINE_HANDLER(CMSG_CLEAR_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::ClearTradeItem, &WorldSession::HandleClearTradeItemOpcode); DEFINE_HANDLER(CMSG_CLIENT_PORT_GRAVEYARD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::PortGraveyard, &WorldSession::HandlePortGraveyard); DEFINE_HANDLER(CMSG_CLOSE_INTERACTION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -331,7 +332,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_COMPLETE_MOVIE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_CONFIRM_RESPEC_WIPE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleConfirmRespecWipeOpcode ); DEFINE_HANDLER(CMSG_CONNECT_TO_FAILED, STATUS_NEVER, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CONVERT_RAID, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupRaidConvertOpcode ); + DEFINE_HANDLER(CMSG_CONVERT_RAID, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::ConvertRaid, &WorldSession::HandleConvertRaidOpcode); DEFINE_HANDLER(CMSG_CREATE_CHARACTER, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CreateCharacter, &WorldSession::HandleCharCreateOpcode); DEFINE_HANDLER(CMSG_CREATE_SHIPMENT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_DB_QUERY_BULK, STATUS_AUTHED, PROCESS_INPLACE, WorldPackets::Query::DBQueryBulk, &WorldSession::HandleDBQueryBulk); @@ -357,7 +358,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_DISCARDED_TIME_SYNC_ACKS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_DISMISS_CRITTER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleDismissCritter ); DEFINE_HANDLER(CMSG_DO_MASTER_LOOT_ROLL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_DO_READY_CHECK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidReadyCheckOpcode ); + DEFINE_HANDLER(CMSG_DO_READY_CHECK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::DoReadyCheck, &WorldSession::HandleDoReadyCheckOpcode); DEFINE_HANDLER(CMSG_DUEL_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Duel::DuelResponse, &WorldSession::HandleDuelResponseOpcode); DEFINE_HANDLER(CMSG_EJECT_PASSENGER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::EjectPassenger, &WorldSession::HandleEjectPassenger); DEFINE_HANDLER(CMSG_EMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::EmoteClient, &WorldSession::HandleEmoteOpcode); @@ -458,7 +459,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_HEARTH_AND_RESURRECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Battleground::HearthAndResurrect, &WorldSession::HandleHearthAndResurrect); DEFINE_HANDLER(CMSG_IGNORE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::IgnoreTrade, &WorldSession::HandleIgnoreTradeOpcode); DEFINE_HANDLER(CMSG_INCREASE_CAST_TIME_FOR_SPELL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_INITIATE_ROLE_POLL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRolePollBeginOpcode); + DEFINE_HANDLER(CMSG_INITIATE_ROLE_POLL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::InitiateRolePoll, &WorldSession::HandleInitiateRolePoll); DEFINE_HANDLER(CMSG_INITIATE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::InitiateTrade, &WorldSession::HandleInitiateTradeOpcode); DEFINE_HANDLER(CMSG_INSPECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::Inspect, &WorldSession::HandleInspectOpcode); DEFINE_HANDLER(CMSG_INSPECT_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::InspectPVPRequest, &WorldSession::HandleInspectPVP); @@ -471,7 +472,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_KEYBOUND_OVERRIDE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_LEARN_PET_SPECIALIZATION_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_LEARN_TALENTS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Talent::LearnTalents, &WorldSession::HandleLearnTalentsOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_LEAVE_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupDisbandOpcode ); + DEFINE_HANDLER(CMSG_LEAVE_GROUP, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::LeaveGroup, &WorldSession::HandleLeaveGroupOpcode); DEFINE_HANDLER(CMSG_LEAVE_PET_BATTLE_QUEUE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_LFG_LIST_APPLY_TO_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_LFG_LIST_CANCEL_APPLICATION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -514,7 +515,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_MAIL_TAKE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailTakeItem, &WorldSession::HandleMailTakeItem); DEFINE_HANDLER(CMSG_MAIL_TAKE_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailTakeMoney, &WorldSession::HandleMailTakeMoney); DEFINE_OPCODE_HANDLER_OLD(CMSG_MASTER_LOOT_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMasterGiveOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MINIMAP_PING, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMinimapPingOpcode ); + DEFINE_HANDLER(CMSG_MINIMAP_PING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::MinimapPingClient, &WorldSession::HandleMinimapPingOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_MISSILE_TRAJECTORY_COLLISION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateProjectilePosition ); DEFINE_HANDLER(CMSG_MOUNT_SET_FAVORITE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_MOUNT_SPECIAL_ANIM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMountSpecialAnimOpcode ); @@ -590,10 +591,10 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_OPEN_MISSION_NPC, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_OPEN_SHIPMENT_NPC, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_OPEN_TRADESKILL_NPC, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_OPT_OUT_OF_LOOT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleOptOutOfLootOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PARTY_INVITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupInviteOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PARTY_INVITE_RESPONSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupInviteResponseOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PARTY_UNINVITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupUninviteOpcode ); + DEFINE_HANDLER(CMSG_OPT_OUT_OF_LOOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::OptOutOfLoot, &WorldSession::HandleOptOutOfLootOpcode); + DEFINE_HANDLER(CMSG_PARTY_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::PartyInviteClient, &WorldSession::HandlePartyInviteOpcode); + DEFINE_HANDLER(CMSG_PARTY_INVITE_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::PartyInviteResponse, &WorldSession::HandlePartyInviteResponseOpcode); + DEFINE_HANDLER(CMSG_PARTY_UNINVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::PartyUninvite, &WorldSession::HandlePartyUninviteOpcode); DEFINE_HANDLER(CMSG_PETITION_BUY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionBuy, &WorldSession::HandlePetitionBuy); DEFINE_HANDLER(CMSG_PETITION_RENAME_GUILD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionRenameGuild, &WorldSession::HandlePetitionRenameGuild); DEFINE_HANDLER(CMSG_PETITION_SHOW_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionShowList, &WorldSession::HandlePetitionShowList); @@ -655,7 +656,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_PUSH_RESULT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPushResult ); DEFINE_HANDLER(CMSG_QUEUED_MESSAGES_END, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_RANDOM_ROLL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::RandomRollClient, &WorldSession::HandleRandomRollOpcode); - DEFINE_HANDLER(CMSG_READY_CHECK_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_READY_CHECK_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::ReadyCheckResponseClient, &WorldSession::HandleReadyCheckResponseOpcode); DEFINE_HANDLER(CMSG_READ_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::ReadItem, &WorldSession::HandleReadItem); DEFINE_HANDLER(CMSG_RECLAIM_CORPSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::ReclaimCorpse, &WorldSession::HandleReclaimCorpse); DEFINE_HANDLER(CMSG_RECRUIT_A_FRIEND, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -676,12 +677,12 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REQUEST_GUILD_REWARDS_LIST, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Guild::RequestGuildRewardsList, &WorldSession::HandleRequestGuildRewardsList); DEFINE_HANDLER(CMSG_REQUEST_HONOR_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::RequestHonorStats, &WorldSession::HandleRequestHonorStatsOpcode); DEFINE_HANDLER(CMSG_REQUEST_LFG_LIST_BLACKLIST, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PARTY_JOIN_UPDATES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupRequestJoinUpdates); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPartyMemberStatsOpcode); + DEFINE_HANDLER(CMSG_REQUEST_PARTY_JOIN_UPDATES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestPartyJoinUpdates, &WorldSession::HandleRequestPartyJoinUpdates); + DEFINE_HANDLER(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestPartyMemberStats, &WorldSession::HandleRequestPartyMemberStatsOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PET_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPetInfoOpcode ); DEFINE_HANDLER(CMSG_REQUEST_PLAYED_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::RequestPlayedTime, &WorldSession::HandlePlayedTime); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PVP_REWARDS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleRequestPvpReward ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_RAID_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRaidInfoOpcode ); + DEFINE_HANDLER(CMSG_REQUEST_RAID_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestRaidInfo, &WorldSession::HandleRequestRaidInfoOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_RATED_BATTLEFIELD_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRatedBattlefieldInfo); DEFINE_HANDLER(CMSG_REQUEST_RESEARCH_HISTORY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_STABLED_PETS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); @@ -695,7 +696,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_RESURRECT_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::ResurrectResponse, &WorldSession::HandleResurrectResponse); DEFINE_HANDLER(CMSG_REVERT_MONUMENT_APPEARANCE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_RIDE_VEHICLE_INTERACT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::RideVehicleInteract, &WorldSession::HandleRideVehicleInteract); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SAVE_CUF_PROFILES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleSaveCUFProfiles ); + DEFINE_HANDLER(CMSG_SAVE_CUF_PROFILES, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Misc::SaveCUFProfiles, &WorldSession::HandleSaveCUFProfiles); DEFINE_HANDLER(CMSG_SAVE_EQUIPMENT_SET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::EquipmentSet::SaveEquipmentSet, &WorldSession::HandleEquipmentSetSave); DEFINE_HANDLER(CMSG_SAVE_GUILD_EMBLEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Guild::SaveGuildEmblem, &WorldSession::HandleSaveGuildEmblem); DEFINE_HANDLER(CMSG_SCENE_PLAYBACK_CANCELED, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Scenes::ScenePlaybackCanceled, &WorldSession::HandleScenePlaybackCanceled); @@ -716,7 +717,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Movement::SetActiveMover, &WorldSession::HandleSetActiveMoverOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTIVE_VOICE_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveVoiceChannel ); DEFINE_HANDLER(CMSG_SET_ADVANCED_COMBAT_LOGGING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ASSISTANT_LEADER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupAssistantLeaderOpcode); + DEFINE_HANDLER(CMSG_SET_ASSISTANT_LEADER, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetAssistantLeader, &WorldSession::HandleSetAssistantLeaderOpcode); DEFINE_HANDLER(CMSG_SET_BACKPACK_AUTOSORT_DISABLED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_BANK_AUTOSORT_DISABLED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_BANK_BAG_SLOT_FLAG, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -724,22 +725,22 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_CURRENCY_FLAGS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_DIFFICULTY_ID, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_DUNGEON_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetDungeonDifficulty, &WorldSession::HandleSetDungeonDifficultyOpcode); - DEFINE_HANDLER(CMSG_SET_EVERYONE_IS_ASSISTANT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_SET_EVERYONE_IS_ASSISTANT, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetEveryoneIsAssistant, &WorldSession::HandleSetEveryoneIsAssistant); DEFINE_HANDLER(CMSG_SET_FACTION_AT_WAR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetFactionAtWar, &WorldSession::HandleSetFactionAtWar); DEFINE_HANDLER(CMSG_SET_FACTION_INACTIVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetFactionInactive, &WorldSession::HandleSetFactionInactiveOpcode); DEFINE_HANDLER(CMSG_SET_FACTION_NOT_AT_WAR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetFactionNotAtWar, &WorldSession::HandleSetFactionNotAtWar); DEFINE_HANDLER(CMSG_SET_INSERT_ITEMS_LEFT_TO_RIGHT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_LFG_BONUS_FACTION_ID, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_LOOT_METHOD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMethodOpcode ); + DEFINE_HANDLER(CMSG_SET_LOOT_METHOD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::SetLootMethod, &WorldSession::HandleSetLootMethodOpcode); DEFINE_HANDLER(CMSG_SET_LOOT_SPECIALIZATION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PARTY_ASSIGNMENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyAssignmentOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PARTY_LEADER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupSetLeaderOpcode ); + DEFINE_HANDLER(CMSG_SET_PARTY_LEADER, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetPartyLeader, &WorldSession::HandleSetPartyLeaderOpcode); DEFINE_HANDLER(CMSG_SET_PET_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPlayerDeclinedNames ); DEFINE_HANDLER(CMSG_SET_PREFERRED_CEMETERY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_PVP, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_RAID_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetRaidDifficulty, &WorldSession::HandleSetRaidDifficultyOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ROLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupSetRolesOpcode ); + DEFINE_HANDLER(CMSG_SET_ROLE, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetRole, &WorldSession::HandleSetRoleOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_SAVED_INSTANCE_EXTEND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetSavedInstanceExtend ); DEFINE_HANDLER(CMSG_SET_SELECTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetSelection, &WorldSession::HandleSetSelectionOpcode); DEFINE_HANDLER(CMSG_SET_SHEATHED, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Combat::SetSheathed, &WorldSession::HandleSetSheathedOpcode); @@ -775,7 +776,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapInvItem, &WorldSession::HandleSwapInvItemOpcode); DEFINE_HANDLER(CMSG_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapItem, &WorldSession::HandleSwapItem); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SWAP_SUB_GROUPS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupSwapSubGroupOpcode ); + DEFINE_HANDLER(CMSG_SWAP_SUB_GROUPS, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SwapSubGroups, &WorldSession::HandleSwapSubGroupsOpcode); DEFINE_HANDLER(CMSG_SWAP_VOID_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::VoidStorage::SwapVoidItem, &WorldSession::HandleVoidSwapItem); DEFINE_HANDLER(CMSG_TABARD_VENDOR_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleTabardVendorActivateOpcode); DEFINE_HANDLER(CMSG_TALK_TO_GOSSIP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleGossipHelloOpcode); @@ -809,7 +810,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_UPDATE_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::ClientConfig::UserClientUpdateAccountData, &WorldSession::HandleUpdateAccountData); DEFINE_HANDLER(CMSG_UPDATE_CLIENT_SETTINGS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_UPDATE_MISSILE_TRAJECTORY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateMissileTrajectory ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_UPDATE_RAID_TARGET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidTargetUpdateOpcode ); + DEFINE_HANDLER(CMSG_UPDATE_RAID_TARGET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::UpdateRaidTarget, &WorldSession::HandleUpdateRaidTargetOpcode); DEFINE_HANDLER(CMSG_UPDATE_WOW_TOKEN_AUCTIONABLE_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Token::UpdateListedAuctionableTokens, &WorldSession::HandleUpdateListedAuctionableTokens); DEFINE_HANDLER(CMSG_UPDATE_WOW_TOKEN_COUNT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_UPGRADE_GARRISON, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -990,7 +991,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHALLENGE_MODE_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANGE_PLAYER_DIFFICULTY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_LIST, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY_JOINED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY_LEFT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_LOGIN_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1000,8 +1001,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_UPGRADE_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_UPGRADE_SPELL_TIER_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_UPGRADE_STARTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_FACTION_CHANGE_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_AUTO_RESPONDED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1169,10 +1170,10 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_POI, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_ACTION_THROTTLED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DECLINE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DESTROYED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_NEW_LEADER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_UNINVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DECLINE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DESTROYED, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_NEW_LEADER, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_UNINVITE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_DELETED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_EARNED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_MEMBERS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1248,7 +1249,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_TIMER_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_GROUP_SIZE_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_INFO, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_SAVE_CREATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1257,12 +1258,12 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVENTORY_CHANGE_FAILURE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_IS_QUEST_COMPLETE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_COOLDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_ENCHANT_TIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_COOLDOWN, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_ENCHANT_TIME_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_EXPIRE_PURCHASE_REFUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PURCHASE_REFUND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_KICK_REASON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARNED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARN_TALENT_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1298,7 +1299,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIVE_REGION_ACCOUNT_RESTORE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIVE_REGION_CHARACTER_COPY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIVE_REGION_GET_ACCOUNT_CHARACTER_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_CUF_PROFILES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_CUF_PROFILES, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_EQUIPMENT_SET, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_SELECTED_TROPHY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGIN_SET_TIME_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); @@ -1327,7 +1328,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAP_OBJ_EVENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MASTER_LOOT_CANDIDATE_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MESSAGE_BOX, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIMAP_PING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIMAP_PING, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MIRROR_IMAGE_COMPONENTED_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MIRROR_IMAGE_CREATURE_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MISSILE_CANCEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1431,11 +1432,11 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_SHIPMENT_NPC_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_OVERRIDE_LIGHT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAGE_TEXT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_INVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_COMMAND_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_INVITE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_KILL_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAUSE_MIRROR_TIMER, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PENDING_RAID_LOCK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_ALREADY_SIGNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1539,12 +1540,12 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_DIFFICULTY_SET, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_GROUP_ONLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_INSTANCE_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_MARKERS_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_MARKERS_CHANGED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RANDOM_ROLL, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RATED_BATTLEFIELD_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_COMPLETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_STARTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_COMPLETED, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_STARTED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_READ_ITEM_RESULT_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_READ_ITEM_RESULT_OK, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REALM_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1573,9 +1574,9 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_TOKEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_REQUEST, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESYNC_RUNES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_CHANGED_INFORM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_CHANGED_INFORM, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_CHOSEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_POLL_INFORM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_POLL_INFORM, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RUNE_REGEN_DEBUG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_BOOT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_COMPLETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1594,8 +1595,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SELL_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_ITEM_PASSIVES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_KNOWN_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_ALL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_ALL, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_SPELL_CHARGES, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_SPELL_HISTORY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_UNLEARN_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); @@ -1657,7 +1658,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_MULTISTRIKE_EFFECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_NON_MELEE_DAMAGE_LOG, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_OR_DAMAGE_IMMUNE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_PERIODIC_AURA_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_PERIODIC_AURA_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_START, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_UPDATE_CHAIN_TARGETS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPIRIT_HEALER_CONFIRM, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index fa557616450..650e100f514 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -913,31 +913,23 @@ bool WorldSession::IsAddonRegistered(const std::string& prefix) const return itr != _registeredAddonPrefixes.end(); } -void WorldSession::HandleUnregisterAddonPrefixesOpcode(WorldPacket& /*recvPacket*/) // empty packet +void WorldSession::HandleUnregisterAllAddonPrefixesOpcode(WorldPackets::Chat::ChatUnregisterAllAddonPrefixes& /*packet*/) // empty packet { _registeredAddonPrefixes.clear(); } -void WorldSession::HandleAddonRegisteredPrefixesOpcode(WorldPacket& recvPacket) +void WorldSession::HandleAddonRegisteredPrefixesOpcode(WorldPackets::Chat::ChatRegisterAddonPrefixes& packet) { - // This is always sent after CMSG_UNREGISTER_ALL_ADDON_PREFIXES + // This is always sent after CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES - uint32 count = recvPacket.ReadBits(25); - - if (count > REGISTERED_ADDON_PREFIX_SOFTCAP) + if (packet.Prefixes.size() > 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])); + _registeredAddonPrefixes.insert(_registeredAddonPrefixes.end(), packet.Prefixes.begin(), packet.Prefixes.end()); if (_registeredAddonPrefixes.size() > REGISTERED_ADDON_PREFIX_SOFTCAP) // shouldn't happen { diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 6cfa8202af4..8f74a8900b0 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -171,9 +171,6 @@ namespace WorldPackets class ChannelPlayerCommand; class JoinChannel; class LeaveChannel; - class UserlistAdd; - class UserlistRemove; - class UserlistUpdate; } namespace Chat @@ -189,6 +186,8 @@ namespace WorldPackets class ChatMessageEmote; class CTextEmote; class EmoteClient; + class ChatRegisterAddonPrefixes; + class ChatUnregisterAllAddonPrefixes; } namespace Combat @@ -278,6 +277,11 @@ namespace WorldPackets class RequestHonorStats; } + namespace Instance + { + class InstanceInfo; + } + namespace Item { class AutoEquipItem; @@ -341,6 +345,8 @@ namespace WorldPackets class CompleteCinematic; class NextCinematicCamera; class FarSight; + class LoadCUFProfiles; + class SaveCUFProfiles; } namespace Movement @@ -363,6 +369,47 @@ namespace WorldPackets class TrainerBuySpell; } + namespace Party + { + class PartyCommandResult; + class PartyInviteClient; + class PartyInvite; + class PartyInviteResponse; + class PartyUninvite; + class GroupDecline; + class RequestPartyMemberStats; + class PartyMemberStats; + class SetPartyLeader; + class SetRole; + class RoleChangedInform; + class SetLootMethod; + class LeaveGroup; + class MinimapPingClient; + class MinimapPing; + class UpdateRaidTarget; + class SendRaidTargetUpdateSingle; + class SendRaidTargetUpdateAll; + class ConvertRaid; + class RequestPartyJoinUpdates; + class SetAssistantLeader; + class DoReadyCheck; + class ReadyCheckStarted; + class ReadyCheckResponseClient; + class ReadyCheckResponse; + class ReadyCheckCompleted; + class RequestRaidInfo; + class OptOutOfLoot; + class InitiateRolePoll; + class RolePollInform; + class GroupNewLeader; + class PartyUpdate; + class SetEveryoneIsAssistant; + class ChangeSubGroup; + class SwapSubGroups; + class RaidMarkersChanged; + class ClearRaidMarker; + } + namespace Petition { class DeclinePetition; @@ -858,8 +905,6 @@ class WorldSession void SendNotInArenaTeamPacket(uint8 type); void SendPetitionShowList(ObjectGuid guid); - void BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data); - void DoLootRelease(ObjectGuid lguid); // Account mute time @@ -1054,28 +1099,31 @@ class WorldSession void HandleMoveTimeSkippedOpcode(WorldPackets::Movement::MoveTimeSkipped& moveTimeSkipped); void HandleMovementAckMessage(WorldPackets::Movement::MovementAckMessage& movementAck); - void HandleRequestRaidInfoOpcode(WorldPacket& recvData); + void HandleRequestRaidInfoOpcode(WorldPackets::Party::RequestRaidInfo& packet); - void HandleGroupInviteOpcode(WorldPacket& recvPacket); + void HandlePartyInviteOpcode(WorldPackets::Party::PartyInviteClient& packet); //void HandleGroupCancelOpcode(WorldPacket& recvPacket); - void HandleGroupInviteResponseOpcode(WorldPacket& recvPacket); - void HandleGroupUninviteOpcode(WorldPacket& recvPacket); - void HandleGroupSetLeaderOpcode(WorldPacket& recvPacket); - void HandleGroupSetRolesOpcode(WorldPacket& recvData); - void HandleGroupDisbandOpcode(WorldPacket& recvPacket); - void HandleOptOutOfLootOpcode(WorldPacket& recvData); - void HandleLootMethodOpcode(WorldPacket& recvPacket); + void HandlePartyInviteResponseOpcode(WorldPackets::Party::PartyInviteResponse& packet); + void HandlePartyUninviteOpcode(WorldPackets::Party::PartyUninvite& packet); + void HandleSetPartyLeaderOpcode(WorldPackets::Party::SetPartyLeader& packet); + void HandleSetRoleOpcode(WorldPackets::Party::SetRole& packet); + void HandleLeaveGroupOpcode(WorldPackets::Party::LeaveGroup& packet); + void HandleOptOutOfLootOpcode(WorldPackets::Party::OptOutOfLoot& packet); + void HandleSetLootMethodOpcode(WorldPackets::Party::SetLootMethod& packet); void HandleLootRoll(WorldPackets::Loot::LootRoll& packet); - void HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData); - void HandleRaidTargetUpdateOpcode(WorldPacket& recvData); - void HandleRaidReadyCheckOpcode(WorldPacket& recvData); - void HandleGroupRaidConvertOpcode(WorldPacket& recvData); - void HandleGroupRequestJoinUpdates(WorldPacket& recvData); - void HandleGroupChangeSubGroupOpcode(WorldPacket& recvData); - void HandleGroupSwapSubGroupOpcode(WorldPacket& recvData); - void HandleGroupAssistantLeaderOpcode(WorldPacket& recvData); + void HandleRequestPartyMemberStatsOpcode(WorldPackets::Party::RequestPartyMemberStats& packet); + void HandleUpdateRaidTargetOpcode(WorldPackets::Party::UpdateRaidTarget& packet); + void HandleDoReadyCheckOpcode(WorldPackets::Party::DoReadyCheck& packet); + void HandleReadyCheckResponseOpcode(WorldPackets::Party::ReadyCheckResponseClient& packet); + void HandleConvertRaidOpcode(WorldPackets::Party::ConvertRaid& packet); + void HandleRequestPartyJoinUpdates(WorldPackets::Party::RequestPartyJoinUpdates& packet); + void HandleChangeSubGroupOpcode(WorldPackets::Party::ChangeSubGroup& packet); + void HandleSwapSubGroupsOpcode(WorldPackets::Party::SwapSubGroups& packet); + void HandleSetAssistantLeaderOpcode(WorldPackets::Party::SetAssistantLeader& packet); void HandlePartyAssignmentOpcode(WorldPacket& recvData); - void HandleRolePollBeginOpcode(WorldPacket& recvData); + void HandleInitiateRolePoll(WorldPackets::Party::InitiateRolePoll& packet); + void HandleSetEveryoneIsAssistant(WorldPackets::Party::SetEveryoneIsAssistant& packet); + void HandleClearRaidMarker(WorldPackets::Party::ClearRaidMarker& packet); void HandleDeclinePetition(WorldPackets::Petition::DeclinePetition& packet); void HandleOfferPetition(WorldPackets::Petition::OfferPetition& packet); @@ -1266,8 +1314,8 @@ class WorldSession void HandleTextEmoteOpcode(WorldPackets::Chat::CTextEmote& packet); void HandleChatIgnoredOpcode(WorldPacket& recvPacket); - void HandleUnregisterAddonPrefixesOpcode(WorldPacket& recvPacket); - void HandleAddonRegisteredPrefixesOpcode(WorldPacket& recvPacket); + void HandleUnregisterAllAddonPrefixesOpcode(WorldPackets::Chat::ChatUnregisterAllAddonPrefixes& packet); + void HandleAddonRegisteredPrefixesOpcode(WorldPackets::Chat::ChatRegisterAddonPrefixes& packet); void HandleReclaimCorpse(WorldPackets::Misc::ReclaimCorpse& packet); void HandleQueryCorpseLocation(WorldPackets::Query::QueryCorpseLocationFromClient& packet); @@ -1340,7 +1388,7 @@ class WorldSession void HandleWardenDataOpcode(WorldPacket& recvData); void HandleWorldTeleportOpcode(WorldPacket& recvData); - void HandleMinimapPingOpcode(WorldPacket& recvData); + void HandleMinimapPingOpcode(WorldPackets::Party::MinimapPingClient& packet); void HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& packet); void HandleFarSightOpcode(WorldPackets::Misc::FarSight& packet); void HandleSetDungeonDifficultyOpcode(WorldPackets::Misc::SetDungeonDifficulty& setDungeonDifficulty); @@ -1473,7 +1521,7 @@ class WorldSession void HandleRequestWowTokenMarketPrice(WorldPackets::Token::RequestWowTokenMarketPrice& requestWowTokenMarketPrice); // Compact Unit Frames (4.x) - void HandleSaveCUFProfiles(WorldPacket& recvPacket); + void HandleSaveCUFProfiles(WorldPackets::Misc::SaveCUFProfiles& packet); void SendLoadCUFProfiles(); // Garrison diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 7e60ac9b5da..669b90e6392 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -524,7 +524,7 @@ enum AuraType SPELL_AURA_464 = 464, SPELL_AURA_465 = 465, SPELL_AURA_466 = 466, - SPELL_AURA_467 = 467, + SPELL_AURA_MOD_STAT_BONUS_PCT = 467, // Affects stat gain from all sources except base stats SPELL_AURA_468 = 468, SPELL_AURA_469 = 469, SPELL_AURA_471 = 471, diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a3b0c4788e7..5abf9d10375 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -527,7 +527,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //464 &AuraEffect::HandleNULL, //465 &AuraEffect::HandleNULL, //466 - &AuraEffect::HandleNULL, //467 + &AuraEffect::HandleModStatBonusPercent, //467 SPELL_AURA_MOD_STAT_BONUS_PCT &AuraEffect::HandleNULL, //468 &AuraEffect::HandleNULL, //469 &AuraEffect::HandleNULL, //470 @@ -3982,6 +3982,34 @@ void AuraEffect::HandleAuraModExpertise(AuraApplication const* aurApp, uint8 mod target->ToPlayer()->UpdateExpertise(OFF_ATTACK); } +void AuraEffect::HandleModStatBonusPercent(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 (GetMiscValue() < -1 || GetMiscValue() > 4) + { + TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_STAT_BONUS_PCT not valid"); + return; + } + + // only players have base stats + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) + { + if (GetMiscValue() == i || GetMiscValue() == -1) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT_EXCLUDE_CREATE, float(m_amount), apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatPercentBuffMod(Stats(i), float(m_amount), apply); + } + } +} + /********************************/ /*** HEAL & ENERGIZE ***/ /********************************/ diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index e8431e202ba..b2519b4b78a 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -234,6 +234,7 @@ class AuraEffect void HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModResistenceOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModExpertise(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleModStatBonusPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; // heal and energize void HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index fb40de60048..6f2f761868e 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -857,12 +857,14 @@ void Spell::SelectSpellTargets() // Do not check for selfcast if (!ihit->scaleAura && ihit->targetGUID != m_caster->GetGUID()) { - m_UniqueTargetInfo.erase(ihit++); - continue; + ihit = m_UniqueTargetInfo.erase(ihit); + continue; } } + ++ihit; } + if (checkLvl && m_UniqueTargetInfo.empty()) { SendCastResult(SPELL_FAILED_LOWLEVEL); @@ -2326,6 +2328,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) return; } + if (!unit) + return; + if (unit->IsAlive() != target->alive) return; @@ -2866,7 +2871,7 @@ bool Spell::UpdateChanneledTargetList() modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); } - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { if (ihit->missCondition == SPELL_MISS_NONE && (channelTargetEffectMask & ihit->effectMask)) { @@ -3359,10 +3364,10 @@ void Spell::handle_immediate() // process immediate effects (items, ground, etc.) also initialize some variables _handle_immediate_phase(); - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); - for (std::vector<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin(); ihit != m_UniqueGOTargetInfo.end(); ++ihit) + for (std::vector<GOTargetInfo>::iterator ihit = m_UniqueGOTargetInfo.begin(); ihit != m_UniqueGOTargetInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); FinishTargetProcessing(); @@ -3402,7 +3407,7 @@ uint64 Spell::handle_delayed(uint64 t_offset) bool single_missile = (m_targets.HasDst()); // now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases) - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { if (ihit->processed == false) { @@ -3417,7 +3422,7 @@ uint64 Spell::handle_delayed(uint64 t_offset) } // now recheck gameobject targeting correctness - for (std::vector<GOTargetInfo>::iterator ighit= m_UniqueGOTargetInfo.begin(); ighit != m_UniqueGOTargetInfo.end(); ++ighit) + for (std::vector<GOTargetInfo>::iterator ighit = m_UniqueGOTargetInfo.begin(); ighit != m_UniqueGOTargetInfo.end(); ++ighit) { if (ighit->processed == false) { @@ -3475,7 +3480,7 @@ void Spell::_handle_immediate_phase() } // process items - for (std::vector<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit) + for (std::vector<ItemTargetInfo>::iterator ihit = m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); if (!m_originalCaster) @@ -5815,7 +5820,7 @@ bool Spell::CanAutoCast(Unit* target) { SelectSpellTargets(); //check if among target units, our WANTED target is as well (->only self cast spells return false) - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) if (ihit->targetGUID == targetguid) return true; } @@ -6832,7 +6837,7 @@ void Spell::HandleLaunchPhase() if (effect && (m_applyMultiplierMask & (1 << effect->EffectIndex))) multiplier[effect->EffectIndex] = effect->CalcDamageMultiplier(m_originalCaster, this); - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { TargetInfo& target = *ihit; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 3ca8550b3ce..ec716a0e03d 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -338,6 +338,7 @@ class Spell void EffectApplyGlyph(SpellEffIndex effIndex); void EffectEnchantHeldItem(SpellEffIndex effIndex); void EffectSummonObject(SpellEffIndex effIndex); + void EffectChangeRaidMarker(SpellEffIndex effIndex); void EffectResurrect(SpellEffIndex effIndex); void EffectParry(SpellEffIndex effIndex); void EffectBlock(SpellEffIndex effIndex); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9e4f0608a38..c640134f6e4 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -180,7 +180,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 - &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 + &Spell::EffectChangeRaidMarker, //106 SPELL_EFFECT_CHANGE_RAID_MARKER &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC &Spell::EffectResurrectPet, //109 SPELL_EFFECT_RESURRECT_PET @@ -241,7 +241,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &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, //167 SPELL_EFFECT_UPDATE_PLAYER_PHASE &Spell::EffectNULL, //168 SPELL_EFFECT_ALLOW_CONTROL_PET &Spell::EffectDestroyItem, //169 SPELL_EFFECT_DESTROY_ITEM &Spell::EffectNULL, //170 SPELL_EFFECT_UPDATE_ZONE_AURAS_AND_PHASES @@ -421,7 +421,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE)) { uint32 count = 0; - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) if (ihit->effectMask & (1<<effIndex)) ++count; @@ -4648,6 +4648,25 @@ void Spell::EffectPullTowards(SpellEffIndex /*effIndex*/) unitTarget->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ); } +void Spell::EffectChangeRaidMarker(SpellEffIndex /*effIndex*/) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) + return; + + Player* player = m_caster->ToPlayer(); + if (!player || !m_targets.HasDst()) + return; + + Group* group = player->GetGroup(); + if (!group || (group->isRaidGroup() && !group->IsLeader(player->GetGUID()) && !group->IsAssistant(player->GetGUID()))) + return; + + float x, y, z; + destTarget->GetPosition(x, y, z); + + group->AddRaidMarker(damage, player->GetMapId(), x, y, z); +} + void Spell::EffectDispelMechanic(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 4db7091f971..7b012d8a0f6 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -806,7 +806,7 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 103 SPELL_EFFECT_REPUTATION {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 - {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 106 SPELL_EFFECT_CHANGE_RAID_MARKER {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 108 SPELL_EFFECT_DISPEL_MECHANIC {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 109 SPELL_EFFECT_SUMMON_DEAD_PET @@ -1822,6 +1822,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a if (!player->CanFlyInZone(map_id, zone_id)) return SPELL_FAILED_INCORRECT_AREA; } + break; } case SPELL_AURA_MOUNTED: { diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 2f74218ba7b..70b820aed96 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3030,6 +3030,10 @@ void SpellMgr::LoadSpellInfoCorrections() switch (spellInfo->Id) { + case 63026: // Force Cast (HACK: Target shouldn't be changed) + case 63171: // Force Cast (HACK: Target shouldn't be changed; summon position should be untied from spell destination) + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); + break; case 42436: // Drink! (Brewfest) const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); break; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 33773a57631..4fd8b5d8bf6 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -64,9 +64,9 @@ _SpellScript::EffectHook::EffectHook(uint8 _effIndex) effIndex = _effIndex; } -uint8 _SpellScript::EffectHook::GetAffectedEffectsMask(SpellInfo const* spellEntry) +uint32 _SpellScript::EffectHook::GetAffectedEffectsMask(SpellInfo const* spellEntry) { - uint8 mask = 0; + uint32 mask = 0; if ((effIndex == EFFECT_ALL) || (effIndex == EFFECT_FIRST_FOUND)) { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -74,13 +74,13 @@ uint8 _SpellScript::EffectHook::GetAffectedEffectsMask(SpellInfo const* spellEnt if ((effIndex == EFFECT_FIRST_FOUND) && mask) return mask; if (CheckEffect(spellEntry, i)) - mask |= (uint8)1<<i; + mask |= 1 << i; } } else { if (CheckEffect(spellEntry, effIndex)) - mask |= (uint8)1<<effIndex; + mask |= 1 << effIndex; } return mask; } diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index fb9e1ed3937..f9a2f1ec847 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -74,7 +74,7 @@ class _SpellScript EffectHook(uint8 _effIndex); virtual ~EffectHook() { } - uint8 GetAffectedEffectsMask(SpellInfo const* spellInfo); + uint32 GetAffectedEffectsMask(SpellInfo const* spellInfo); bool IsEffectAffected(SpellInfo const* spellInfo, uint8 effIndex); virtual bool CheckEffect(SpellInfo const* spellInfo, uint8 effIndex) = 0; std::string EffIndexToString(); diff --git a/src/server/game/Texts/ChatTextBuilder.h b/src/server/game/Texts/ChatTextBuilder.h index dcee6f08ac3..167680f1cd2 100644 --- a/src/server/game/Texts/ChatTextBuilder.h +++ b/src/server/game/Texts/ChatTextBuilder.h @@ -34,7 +34,7 @@ namespace Trinity { BroadcastTextEntry const* bct = sBroadcastTextStore.LookupEntry(_textId); WorldPackets::Chat::Chat packet; - packet.Initalize(_msgType, bct ? Language(bct->Language) : LANG_UNIVERSAL, _source, _target, bct ? DB2Manager::GetBroadcastTextValue(bct, locale, _source->getGender()) : "", _achievementId, "", locale); + packet.Initialize(_msgType, bct ? Language(bct->Language) : LANG_UNIVERSAL, _source, _target, bct ? DB2Manager::GetBroadcastTextValue(bct, locale, _source->getGender()) : "", _achievementId, "", locale); packet.Write(); data = packet.Move(); } @@ -56,7 +56,7 @@ namespace Trinity void operator()(WorldPacket& data, LocaleConstant locale) { WorldPackets::Chat::Chat packet; - packet.Initalize(_msgType, _language, _source, _target, _text, 0, "", locale); + packet.Initialize(_msgType, _language, _source, _target, _text, 0, "", locale); packet.Write(); data = packet.Move(); } diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 281504b9aaf..c1ea235a3e2 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -37,7 +37,7 @@ class CreatureTextBuilder { std::string const& text = sCreatureTextMgr->GetLocalizedChatString(_source->GetEntry(), _gender, _textGroup, _textId, locale); WorldPackets::Chat::Chat packet; - packet.Initalize(_msgType, Language(_language), _source, _target, text, 0, "", locale); + packet.Initialize(_msgType, Language(_language), _source, _target, text, 0, "", locale); packet.Write(); data = packet.Move(); } @@ -62,7 +62,7 @@ class PlayerTextBuilder { std::string const& text = sCreatureTextMgr->GetLocalizedChatString(_source->GetEntry(), _gender, _textGroup, _textId, locale); WorldPackets::Chat::Chat packet; - packet.Initalize(_msgType, Language(_language), _talker, _target, text, 0, "", locale); + packet.Initialize(_msgType, Language(_language), _talker, _target, text, 0, "", locale); packet.Write(); data = packet.Move(); } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 9b8c63000fc..d68da8fbc63 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2252,6 +2252,9 @@ void World::Update(uint32 diff) sLFGMgr->Update(diff); RecordTimeDiff("UpdateLFGMgr"); + sGroupMgr->Update(diff); + RecordTimeDiff("GroupMgr"); + // execute callbacks from sql queries that were queued recently ProcessQueryCallbacks(); RecordTimeDiff("ProcessQueryCallbacks"); @@ -2381,7 +2384,7 @@ namespace Trinity while (char* line = ChatHandler::LineFromMessage(text)) { WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); packet.Write(); dataList.emplace_back(new WorldPacket(packet.Move())); } @@ -2447,7 +2450,7 @@ void World::SendGlobalText(const char* text, WorldSession* self) while (char* line = ChatHandler::LineFromMessage(pos)) { WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); SendGlobalMessage(packet.Write(), self); } @@ -2481,7 +2484,7 @@ bool World::SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession void World::SendZoneText(uint32 zone, const char* text, WorldSession* self, uint32 team) { WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text); SendZoneMessage(zone, packet.Write(), self, team); } diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index ecd98595723..7f1a364fd57 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -485,7 +485,7 @@ public: char const* msg = "testtest"; uint8 type = atoi(args); WorldPackets::Chat::Chat packet; - packet.Initalize(ChatMsg(type), LANG_UNIVERSAL, handler->GetSession()->GetPlayer(), handler->GetSession()->GetPlayer(), msg, 0, "chan"); + packet.Initialize(ChatMsg(type), LANG_UNIVERSAL, handler->GetSession()->GetPlayer(), handler->GetSession()->GetPlayer(), msg, 0, "chan"); handler->GetSession()->SendPacket(packet.Write()); return true; } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 61df922452f..b9765223add 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1465,7 +1465,7 @@ public: * Player %s %s (guid: %u) - I. LANG_PINFO_PLAYER * ** GM Mode active, Phase: -1 - II. LANG_PINFO_GM_ACTIVE (if GM) * ** Banned: (Type, Reason, Time, By) - III. LANG_PINFO_BANNED (if banned) - * ** Muted: (Time, Reason, By) - IV. LANG_PINFO_MUTED (if muted) + * ** Muted: (Reason, Time, By) - IV. LANG_PINFO_MUTED (if muted) * * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT * * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN * * Uses OS: %s - Latency: %u ms - VII. LANG_PINFO_ACC_OS @@ -1716,7 +1716,7 @@ public: // Output IV. LANG_PINFO_MUTED if mute is applied if (muteTime > 0) - handler->PSendSysMessage(LANG_PINFO_MUTED, secsToTimeString(muteTime - time(NULL), true).c_str(), muteReason.c_str(), muteBy.c_str()); + handler->PSendSysMessage(LANG_PINFO_MUTED, muteReason.c_str(), secsToTimeString(muteTime - time(nullptr), true).c_str(), muteBy.c_str()); // Output V. LANG_PINFO_ACC_ACCOUNT handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security); diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 81cad2db188..2c91a9e6e3e 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -374,28 +374,13 @@ public: ObjectGuid::LowType lowGuid = strtoull(guidStr, nullptr, 10); - Creature* creature = NULL; - - /* FIXME: impossible without entry - if (lowguid) - creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT)); - */ - // attempt check creature existence by DB data - if (!creature) - { - CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid); - if (!data) - { - handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid); - handler->SetSentErrorMessage(true); - return false; - } - } - else + CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid); + if (!data) { - // obtain real GUID for DB operations - lowGuid = creature->GetSpawnId(); + handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid); + handler->SetSentErrorMessage(true); + return false; } int wait = waitStr ? atoi(waitStr) : 0; @@ -411,18 +396,6 @@ public: WorldDatabase.Execute(stmt); - if (creature && creature->GetWaypointPath()) - { - creature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - creature->GetMotionMaster()->Initialize(); - if (creature->IsAlive()) // dead creature will reset movement generator at respawn - { - creature->setDeathState(JUST_DIED); - creature->Respawn(true); - } - creature->SaveToDB(); - } - handler->SendSysMessage(LANG_WAYPOINT_ADDED); return true; @@ -836,34 +809,22 @@ public: lowguid = strtoull(cId, nullptr, 10); - /* FIXME: impossible without entry - if (lowguid) - creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT)); - */ - // Attempting creature load from DB data - if (!creature) + CreatureData const* data = sObjectMgr->GetCreatureData(lowguid); + if (!data) { - CreatureData const* data = sObjectMgr->GetCreatureData(lowguid); - if (!data) - { - handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - handler->SetSentErrorMessage(true); - return false; - } + handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + handler->SetSentErrorMessage(true); + return false; + } - uint32 map_id = data->mapid; + uint32 map_id = data->mapid; - if (handler->GetSession()->GetPlayer()->GetMapId() != map_id) - { - handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); - handler->SetSentErrorMessage(true); - return false; - } - } - else + if (handler->GetSession()->GetPlayer()->GetMapId() != map_id) { - lowguid = creature->GetSpawnId(); + handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); + handler->SetSentErrorMessage(true); + return false; } } else diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp index 1d7e1594d05..ca944f7037b 100644 --- a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp +++ b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp @@ -102,7 +102,7 @@ public: } } - virtual void Update(uint32 /*diff*/) // correct order goes form 1-6 + virtual void Update(uint32 /*diff*/) override // correct order goes form 1-6 { switch (State) { diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp index ec2f41cc625..15280bc7848 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp @@ -197,7 +197,7 @@ class boss_archaedas : public CreatureScript DoMeleeAttackIfReady(); } - void JustDied (Unit* /*killer*/) + void JustDied (Unit* /*killer*/) override { instance->SetData(DATA_ANCIENT_DOOR, DONE); // open the vault door instance->SetData(DATA_MINIONS, SPECIAL); // deactivate his minions diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index f027a98da9d..d261b7a623a 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -1064,7 +1064,7 @@ class npc_meteor_strike : public CreatureScript } } - void IsSummonedBy(Unit* summoner) override + void IsSummonedBy(Unit* /*summoner*/) override { // Let Halion Controller count as summoner. if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER))) @@ -1092,9 +1092,6 @@ class npc_meteor_strike : public CreatureScript Position pos = me->GetNearPosition(5.0f, 0.0f); if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25000)) { - if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER))) - controller->AI()->JustSummoned(flame); - flame->SetOrientation(me->GetOrientation()); flame->AI()->SetGUID(GetGUID()); @@ -1128,7 +1125,7 @@ class npc_meteor_strike_flame : public CreatureScript SetCombatMovement(false); } - void SetGUID(ObjectGuid guid, int32 id /* = 0 */) + void SetGUID(ObjectGuid guid, int32 /*id = 0 */) { _rootOwnerGuid = guid; } @@ -1149,9 +1146,6 @@ class npc_meteor_strike_flame : public CreatureScript if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25000)) { - if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER))) - controller->AI()->JustSummoned(flame); - flame->AI()->SetGUID(_rootOwnerGuid); meteorStrike->AI()->SetData(DATA_SPAWNED_FLAMES, 1); } @@ -1164,7 +1158,7 @@ class npc_meteor_strike_flame : public CreatureScript controller->AI()->JustSummoned(me); } - void UpdateAI(uint32 diff) override { } + void UpdateAI(uint32 /*diff*/) override { } void EnterEvadeMode() override { } private: diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index 0fc4f1a4a8b..7f88a56f22c 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -196,7 +196,7 @@ class instance_halls_of_reflection : public InstanceMapScript } } - uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override + uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override { if (!_teamInInstance) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index faa448ef539..51756834e77 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -1059,8 +1059,8 @@ class spell_putricide_ooze_eruption_searcher : public SpellScriptLoader { if (GetHitUnit()->HasAura(SPELL_VOLATILE_OOZE_ADHESIVE)) { - GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true); GetHitUnit()->RemoveAurasDueToSpell(SPELL_VOLATILE_OOZE_ADHESIVE, GetCaster()->GetGUID(), 0, AURA_REMOVE_BY_ENEMY_SPELL); + GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true); } } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 7bd1dee15ca..423c1049452 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -348,7 +348,7 @@ class boss_sindragosa : public CreatureScript events.ScheduleEvent(EVENT_AIR_MOVEMENT, 1); break; case POINT_AIR_PHASE: - me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL); + me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL, TRIGGERED_FULL_MASK); me->SetFacingTo(float(M_PI)); events.ScheduleEvent(EVENT_AIR_MOVEMENT_FAR, 1); events.ScheduleEvent(EVENT_FROST_BOMB, 9000); @@ -490,7 +490,7 @@ class boss_sindragosa : public CreatureScript if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, FrostBeaconSelector(me))) { Talk(EMOTE_WARN_FROZEN_ORB, target); - DoCast(target, SPELL_ICE_TOMB_DUMMY, true); + me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, 1, nullptr, TRIGGERED_FULL_MASK); } events.ScheduleEvent(EVENT_ICE_TOMB, urand(16000, 23000)); break; @@ -1630,7 +1630,7 @@ void AddSC_boss_sindragosa() new spell_rimefang_icy_blast(); new spell_frostwarden_handler_order_whelp(); new spell_frostwarden_handler_focus_fire(); - new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY); + new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY, TRIGGERED_IGNORE_SET_FACING); new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb_dummy", SPELL_FROST_BEACON); new at_sindragosa_lair(); new achievement_all_you_can_eat(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 8bf8e5ee6fb..091190b6b4e 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -524,14 +524,16 @@ enum AreaIds class spell_trigger_spell_from_caster : public SpellScriptLoader { public: - spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId) : SpellScriptLoader(scriptName), _triggerId(triggerId) { } + spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId, TriggerCastFlags triggerFlags = TRIGGERED_FULL_MASK) + : SpellScriptLoader(scriptName), _triggerId(triggerId), _triggerFlags(triggerFlags) { } class spell_trigger_spell_from_caster_SpellScript : public SpellScript { PrepareSpellScript(spell_trigger_spell_from_caster_SpellScript); public: - spell_trigger_spell_from_caster_SpellScript(uint32 triggerId) : SpellScript(), _triggerId(triggerId) { } + spell_trigger_spell_from_caster_SpellScript(uint32 triggerId, TriggerCastFlags triggerFlags) + : SpellScript(), _triggerId(triggerId), _triggerFlags(triggerFlags) { } bool Validate(SpellInfo const* /*spell*/) override { @@ -542,7 +544,7 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader void HandleTrigger() { - GetCaster()->CastSpell(GetHitUnit(), _triggerId, true); + GetCaster()->CastSpell(GetHitUnit(), _triggerId, _triggerFlags); } void Register() override @@ -551,15 +553,17 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader } uint32 _triggerId; + TriggerCastFlags _triggerFlags; }; SpellScript* GetSpellScript() const override { - return new spell_trigger_spell_from_caster_SpellScript(_triggerId); + return new spell_trigger_spell_from_caster_SpellScript(_triggerId, _triggerFlags); } private: uint32 _triggerId; + TriggerCastFlags _triggerFlags; }; template<class AI> diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index aee14edd0c3..d38d630f775 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -317,7 +317,7 @@ class instance_icecrown_citadel : public InstanceMapScript } // Weekly quest spawn prevention - uint32 GetCreatureEntry(uint32 /*guidLow*/, CreatureData const* data) override + uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override { uint32 entry = data->id; switch (entry) @@ -372,7 +372,7 @@ class instance_icecrown_citadel : public InstanceMapScript return entry; } - uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override + uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override { switch (entry) { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp index 134783ccf07..6a1ff6d4eea 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -903,17 +903,15 @@ class boss_yogg_saron : public CreatureScript DoCast(me, SPELL_KNOCK_AWAY); me->ResetLootMode(); - switch (_instance->GetData(DATA_KEEPERS_COUNT)) - { - case 0: - me->AddLootMode(LOOT_MODE_HARD_MODE_4); - case 1: - me->AddLootMode(LOOT_MODE_HARD_MODE_3); - case 2: - me->AddLootMode(LOOT_MODE_HARD_MODE_2); - case 3: - me->AddLootMode(LOOT_MODE_HARD_MODE_1); - } + uint32 keepersCount = _instance->GetData(DATA_KEEPERS_COUNT); + if (keepersCount == 0) + me->AddLootMode(LOOT_MODE_HARD_MODE_4); + if (keepersCount <= 1) + me->AddLootMode(LOOT_MODE_HARD_MODE_3); + if (keepersCount <= 2) + me->AddLootMode(LOOT_MODE_HARD_MODE_2); + if (keepersCount <= 3) + me->AddLootMode(LOOT_MODE_HARD_MODE_1); } void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 7f29a6621bd..2e426fd77cf 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -25,53 +25,6 @@ #include "CombatAI.h" /*###### -## npc_squire_david -######*/ - -enum SquireDavid -{ - QUEST_THE_ASPIRANT_S_CHALLENGE_H = 13680, - QUEST_THE_ASPIRANT_S_CHALLENGE_A = 13679, - - NPC_ARGENT_VALIANT = 33448, - - GOSSIP_TEXTID_SQUIRE = 14407 -}; - -#define GOSSIP_SQUIRE_ITEM_1 "I am ready to fight!" -#define GOSSIP_SQUIRE_ITEM_2 "How do the Argent Crusader raiders fight?" - -class npc_squire_david : public CreatureScript -{ -public: - npc_squire_david() : CreatureScript("npc_squire_david") { } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_H) == QUEST_STATUS_INCOMPLETE || - player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_A) == QUEST_STATUS_INCOMPLETE)//We need more info about it. - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - } - - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SQUIRE, creature->GetGUID()); - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - creature->SummonCreature(NPC_ARGENT_VALIANT, 8575.451f, 952.472f, 547.554f, 0.38f); - } - return true; - } -}; - -/*###### ## npc_argent_valiant ######*/ @@ -837,7 +790,6 @@ class npc_frostbrood_skytalon : public CreatureScript void AddSC_icecrown() { - new npc_squire_david; new npc_argent_valiant; new npc_guardian_pavilion; new npc_tournament_training_dummy; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h index c2dd71ce7cf..77a7c338118 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h @@ -261,13 +261,13 @@ class OPvPCapturePointNA : public OPvPCapturePoint public: OPvPCapturePointNA(OutdoorPvP* pvp); - bool Update(uint32 diff); + bool Update(uint32 diff) override; - void ChangeState(); + void ChangeState() override; - void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet); + void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override; - bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go); + bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go) override; int32 HandleOpenGo(Player* player, GameObject* go) override; diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index 24658dbc21f..42621b76941 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -27,6 +27,7 @@ set(scripts_STAT_SRCS Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp + Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp index fb44a403d86..dfc5f5992a6 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp @@ -108,6 +108,7 @@ class boss_grand_warlock_nethekurse : public CreatureScript void Reset() override { + _Reset(); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); Initialize(); @@ -115,9 +116,8 @@ class boss_grand_warlock_nethekurse : public CreatureScript void JustDied(Unit* /*killer*/) override { + _JustDied(); Talk(SAY_DIE); - - instance->SetBossState(DATA_NETHEKURSE, DONE); } void SetData(uint32 data, uint32 value) override diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp index 7d00cd97126..a950882eddd 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp @@ -160,6 +160,7 @@ class boss_warbringer_omrogg : public CreatureScript void Reset() override { + _Reset(); if (Unit* LeftHead = ObjectAccessor::GetUnit(*me, LeftHeadGUID)) { LeftHead->setDeathState(JUST_DIED); @@ -257,14 +258,14 @@ class boss_warbringer_omrogg : public CreatureScript Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID); Creature* RightHead = ObjectAccessor::GetCreature(*me, RightHeadGUID); + _JustDied(); + if (!LeftHead || !RightHead) return; LeftHead->AI()->Talk(YELL_DIE_L); RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL); - - instance->SetBossState(DATA_OMROGG, DONE); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp index b44ae46c78c..7f2e08b39ca 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp @@ -35,7 +35,10 @@ enum Says { SAY_AGGRO = 0, SAY_SLAY = 1, - SAY_DEATH = 2 + SAY_DEATH = 2, + + SAY_CALL_EXECUTIONER_A = 3, + SAY_CALL_EXECUTIONER_H = 4 }; enum Spells @@ -84,10 +87,28 @@ class boss_warchief_kargath_bladefist : public CreatureScript resetcheck_timer = 5000; } + void DoAction(int32 action) override + { + if (action == ACTION_EXECUTIONER_TAUNT) + { + switch (instance->GetData(DATA_TEAM_IN_INSTANCE)) + { + case ALLIANCE: + Talk(SAY_CALL_EXECUTIONER_A); + break; + case HORDE: + Talk(SAY_CALL_EXECUTIONER_H); + break; + default: + break; + } + } + } + void Reset() override { removeAdds(); - + _Reset(); me->SetSpeed(MOVE_RUN, 2); me->SetWalk(false); @@ -96,10 +117,9 @@ class boss_warchief_kargath_bladefist : public CreatureScript void JustDied(Unit* /*killer*/) override { + _JustDied(); Talk(SAY_DEATH); removeAdds(); - - instance->SetBossState(DATA_KARGATH, DONE); } void EnterCombat(Unit* /*who*/) override diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp index c6b08bdada1..a781861d47f 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp @@ -26,6 +26,18 @@ EndScriptData */ #include "ScriptMgr.h" #include "InstanceScript.h" #include "shattered_halls.h" +#include "Player.h" +#include "SpellAuras.h" +#include "CreatureAI.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" + +DoorData const doorData[] = +{ + { GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } +}; class instance_shattered_halls : public InstanceMapScript { @@ -43,6 +55,41 @@ class instance_shattered_halls : public InstanceMapScript { SetHeaders(DataHeader); SetBossNumber(EncounterCount); + LoadDoorData(doorData); + executionTimer = 0; + executed = 0; + _team = 0; + } + + void OnPlayerEnter(Player* player) override + { + Aura* ex = nullptr; + + if (!_team) + _team = player->GetTeam(); + + player->CastSpell(player, SPELL_REMOVE_KARGATH_EXECUTIONER, true); + + if (!executionTimer || executionerGUID.IsEmpty()) + return; + + switch (executed) + { + case 0: + ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_1, player); + break; + case 1: + ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_2, player); + break; + case 2: + ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_3, player); + break; + default: + break; + } + + if (ex) + ex->SetDuration(executionTimer); } void OnGameObjectCreate(GameObject* go) override @@ -50,21 +97,65 @@ class instance_shattered_halls : public InstanceMapScript switch (go->GetEntry()) { case GO_GRAND_WARLOCK_CHAMBER_DOOR_1: - nethekurseDoor1GUID = go->GetGUID(); + case GO_GRAND_WARLOCK_CHAMBER_DOOR_2: + AddDoor(go, true); + default: break; + } + } + + void OnGameObjectRemove(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_GRAND_WARLOCK_CHAMBER_DOOR_1: case GO_GRAND_WARLOCK_CHAMBER_DOOR_2: - nethekurseDoor2GUID = go->GetGUID(); + AddDoor(go, false); + default: break; } } void OnCreatureCreate(Creature* creature) override { + if (!_team) + { + Map::PlayerList const &players = instance->GetPlayers(); + if (!players.isEmpty()) + if (Player* player = players.begin()->GetSource()) + _team = player->GetTeam(); + } + switch (creature->GetEntry()) { case NPC_GRAND_WARLOCK_NETHEKURSE: nethekurseGUID = creature->GetGUID(); break; + case NPC_KARGATH_BLADEFIST: + kargathGUID = creature->GetGUID(); + break; + case NPC_RANDY_WHIZZLESPROCKET: + if (_team == HORDE) + creature->UpdateEntry(NPC_DRISELLA); + break; + case NPC_SHATTERED_EXECUTIONER: + executionTimer = 55 * MINUTE * IN_MILLISECONDS; + DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_1); + executionerGUID = creature->GetGUID(); + SaveToDB(); + break; + case NPC_CAPTAIN_ALINA: + case NPC_CAPTAIN_BONESHATTER: + victimsGUID[0] = creature->GetGUID(); + break; + case NPC_ALLIANCE_VICTIM_1: + case NPC_HORDE_VICTIM_1: + victimsGUID[1] = creature->GetGUID(); + break; + case NPC_ALLIANCE_VICTIM_2: + case NPC_HORDE_VICTIM_2: + victimsGUID[2] = creature->GetGUID(); + break; } } @@ -75,18 +166,18 @@ class instance_shattered_halls : public InstanceMapScript switch (type) { - case DATA_NETHEKURSE: - if (state == IN_PROGRESS) - { - HandleGameObject(nethekurseDoor1GUID, false); - HandleGameObject(nethekurseDoor2GUID, false); - } - else + case DATA_SHATTERED_EXECUTIONER: + if (state == DONE) { - HandleGameObject(nethekurseDoor1GUID, true); - HandleGameObject(nethekurseDoor2GUID, true); + DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER); + executionTimer = 0; + SaveToDB(); } break; + case DATA_KARGATH: + if (Creature* executioner = instance->GetCreature(executionerGUID)) + executioner->AI()->Reset(); // trigger removal of IMMUNE_TO_PC flag + break; case DATA_OMROGG: break; } @@ -99,24 +190,120 @@ class instance_shattered_halls : public InstanceMapScript { case NPC_GRAND_WARLOCK_NETHEKURSE: return nethekurseGUID; - break; - case GO_GRAND_WARLOCK_CHAMBER_DOOR_1: - return nethekurseDoor1GUID; - break; - case GO_GRAND_WARLOCK_CHAMBER_DOOR_2: - return nethekurseDoor2GUID; - break; + case NPC_KARGATH_BLADEFIST: + return kargathGUID; + case NPC_SHATTERED_EXECUTIONER: + return executionerGUID; + case DATA_FIRST_PRISONER: + case DATA_SECOND_PRISONER: + case DATA_THIRD_PRISONER: + return victimsGUID[data - DATA_FIRST_PRISONER]; + default: + return ObjectGuid::Empty; } - return ObjectGuid::Empty; } - protected: + void WriteSaveDataMore(std::ostringstream& data) override + { + if (!instance->IsHeroic()) + return; + + data << uint32(executed) << ' ' + << executionTimer << ' '; + } + + void ReadSaveDataMore(std::istringstream& data) override + { + if (!instance->IsHeroic()) + return; + + uint32 readbuff; + data >> readbuff; + executed = uint8(readbuff); + data >> readbuff; + + if (executed > VictimCount) + { + executed = VictimCount; + executionTimer = 0; + return; + } + + if (!readbuff) + return; + + Creature* executioner = nullptr; + + instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY()); + if (Creature* kargath = instance->GetCreature(kargathGUID)) + if (executionerGUID.IsEmpty()) + executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner); + + if (executioner) + for (uint8 i = executed; i < VictimCount; ++i) + executioner->SummonCreature(executionerVictims[i](GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos()); + + executionTimer = readbuff; + } + + uint32 GetData(uint32 type) const override + { + switch (type) + { + case DATA_PRISONERS_EXECUTED: + return executed; + case DATA_TEAM_IN_INSTANCE: + return _team; + default: + return 0; + } + } + + void Update(uint32 diff) override + { + if (!executionTimer) + return; + + if (executionTimer <= diff) + { + DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER); + switch (++executed) + { + case 1: + DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_2); + executionTimer = 10 * MINUTE * IN_MILLISECONDS; + break; + case 2: + DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_3); + executionTimer = 15 * MINUTE * IN_MILLISECONDS; + break; + default: + executionTimer = 0; + break; + } + + if (Creature* executioner = instance->GetCreature(executionerGUID)) + executioner->AI()->SetData(DATA_PRISONERS_EXECUTED, executed); + + SaveToDB(); + } + else + executionTimer -= diff; + } + + private: ObjectGuid nethekurseGUID; - ObjectGuid nethekurseDoor1GUID; - ObjectGuid nethekurseDoor2GUID; + ObjectGuid kargathGUID; + ObjectGuid executionerGUID; + ObjectGuid victimsGUID[3]; + + uint8 executed; + uint32 executionTimer; + uint32 _team; }; }; + void AddSC_instance_shattered_halls() { new instance_shattered_halls(); diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp new file mode 100644 index 00000000000..d31fa4c4f09 --- /dev/null +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2008-2015 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "InstanceScript.h" +#include "Player.h" +#include "SpellAuras.h" +#include "shattered_halls.h" + +class at_nethekurse_exit : public AreaTriggerScript +{ + public: + at_nethekurse_exit() : AreaTriggerScript("at_nethekurse_exit") { }; + + bool OnTrigger(Player* player, AreaTriggerEntry const*, bool /*entered*/) override + { + if (InstanceScript* is = player->GetInstanceScript()) + { + if (is->instance->IsHeroic()) + { + Creature* executioner = nullptr; + + is->instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY()); + if (Creature* kargath = ObjectAccessor::GetCreature(*player, is->GetGuidData(NPC_KARGATH_BLADEFIST))) + { + if (is->GetGuidData(NPC_SHATTERED_EXECUTIONER).IsEmpty()) + { + executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner); + kargath->AI()->DoAction(ACTION_EXECUTIONER_TAUNT); + } + } + + if (executioner) + for (uint8 i = 0; i < VictimCount; ++i) + executioner->SummonCreature(executionerVictims[i](is->GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos()); + } + } + + return false; + } +}; + +enum Spells +{ + SPELL_CLEAVE = 15284 +}; + +class boss_shattered_executioner : public CreatureScript +{ + public: + boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { } + + struct boss_shattered_executionerAI : public BossAI + { + boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER) + { + Initialize(); + }; + + void Initialize() + { + cleaveTimer = 500; + } + + void Reset() override + { + _Reset(); + + // _Reset() resets the loot mode, so we add them again, if any + uint32 prisonersExecuted = instance->GetData(DATA_PRISONERS_EXECUTED); + if (prisonersExecuted == 0) + me->AddLootMode(LOOT_MODE_HARD_MODE_3); + if (prisonersExecuted <= 1) + me->AddLootMode(LOOT_MODE_HARD_MODE_2); + if (prisonersExecuted <= 2) + me->AddLootMode(LOOT_MODE_HARD_MODE_1); + + if (instance->GetBossState(DATA_KARGATH) == DONE) + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + else + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + + Initialize(); + } + + void JustSummoned(Creature*) override { } // avoid despawn of prisoners on death/reset + + void JustDied(Unit*) override + { + _JustDied(); + + if (instance->GetData(DATA_PRISONERS_EXECUTED) > 0) + return; + + Map::PlayerList const &players = instance->instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + Player* pl = itr->GetSource(); + uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H; + if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE) + pl->CompleteQuest(qId); + } + } + + void SetData(uint32 type, uint32 data) override + { + if (type == DATA_PRISONERS_EXECUTED && data <= 3) + { + if (Creature* victim = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FIRST_PRISONER + data - 1))) + me->Kill(victim); + + if (data == 1) + { + Map::PlayerList const &players = instance->instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + Player* pl = itr->GetSource(); + uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H; + if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE) + pl->FailQuest(qId); + } + } + + switch (data) + { + case 3: + me->RemoveLootMode(LOOT_MODE_HARD_MODE_1); + case 2: + me->RemoveLootMode(LOOT_MODE_HARD_MODE_2); + case 1: + me->RemoveLootMode(LOOT_MODE_HARD_MODE_3); + default: + break; + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (cleaveTimer <= diff) + { + DoCast(SPELL_CLEAVE); + cleaveTimer = urand(5000, 7000); + } + else + cleaveTimer -= diff; + + DoMeleeAttackIfReady(); + } + private: + uint32 cleaveTimer; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_shattered_executionerAI>(creature); + } +}; + +class spell_kargath_executioner : public SpellScriptLoader +{ + public: + spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { } + + class spell_kargath_executioner_AuraScript : public AuraScript + { + PrepareAuraScript(spell_kargath_executioner_AuraScript); + + bool AreaCheck(Unit* target) + { + if (target->GetMap()->GetId() != 540) + return false; + + return true; + } + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void Register() override + { + DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_kargath_executioner_AuraScript(); + } +}; + +class spell_remove_kargath_executioner : public SpellScriptLoader +{ + public: + spell_remove_kargath_executioner() : SpellScriptLoader("spell_remove_kargath_executioner") { } + + class spell_remove_kargath_executioner_SpellScript : public SpellScript + { + PrepareSpellScript(spell_remove_kargath_executioner_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* target = GetCaster(); + + target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_1); + target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_2); + target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_3); + } + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_remove_kargath_executioner_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_remove_kargath_executioner_SpellScript(); + } +}; + +void AddSC_shattered_halls() +{ + new at_nethekurse_exit(); + new boss_shattered_executioner(); + new spell_kargath_executioner(); + new spell_remove_kargath_executioner(); +} diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h index 90cbbe2a438..894cc9c40a6 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h @@ -21,18 +21,45 @@ #define DataHeader "SH" -uint32 const EncounterCount = 3; +uint32 const EncounterCount = 4; +uint32 const VictimCount = 3; enum DataTypes { - DATA_NETHEKURSE = 1, - DATA_OMROGG = 2, - DATA_KARGATH = 3 + DATA_NETHEKURSE = 0, + DATA_OMROGG = 1, + DATA_KARGATH = 2, + + DATA_SHATTERED_EXECUTIONER = 3, + DATA_PRISONERS_EXECUTED = 4, + + DATA_TEAM_IN_INSTANCE = 5, + + DATA_FIRST_PRISONER, + DATA_SECOND_PRISONER, + DATA_THIRD_PRISONER }; enum CreatureIds { - NPC_GRAND_WARLOCK_NETHEKURSE = 16807 + NPC_GRAND_WARLOCK_NETHEKURSE = 16807, + NPC_KARGATH_BLADEFIST = 16808, + + NPC_SHATTERED_EXECUTIONER = 17301, + + // Alliance Ids + NPC_RANDY_WHIZZLESPROCKET = 17288, + + NPC_CAPTAIN_ALINA = 17290, + NPC_ALLIANCE_VICTIM_1 = 17289, + NPC_ALLIANCE_VICTIM_2 = 17292, + + // Horde Ids + NPC_DRISELLA = 17294, + + NPC_CAPTAIN_BONESHATTER = 17296, + NPC_HORDE_VICTIM_1 = 17295, + NPC_HORDE_VICTIM_2 = 17297 }; enum GameobjectIds @@ -41,4 +68,47 @@ enum GameobjectIds GO_GRAND_WARLOCK_CHAMBER_DOOR_2 = 182540 }; +enum QuestIds +{ + QUEST_IMPRISONED_A = 9524, + QUEST_IMPRISONED_H = 9525 +}; + +enum InstanceSpells +{ + SPELL_KARGATH_EXECUTIONER_1 = 39288, + SPELL_KARGATH_EXECUTIONER_2 = 39289, + SPELL_KARGATH_EXECUTIONER_3 = 39290, + + SPELL_REMOVE_KARGATH_EXECUTIONER = 39291 +}; + +enum Actions +{ + ACTION_EXECUTIONER_TAUNT = 1 +}; + +const Position Executioner = { 152.8524f, -83.63912f, 2.021005f, 0.06981317f }; + +struct FactionSpawnerHelper +{ + FactionSpawnerHelper(uint32 allianceEntry, uint32 hordeEntry, const Position& pos) : _allianceNPC(allianceEntry), _hordeNPC(hordeEntry), _spawnPos(pos) { } + + inline uint32 operator()(uint32 teamID) const { return teamID == ALLIANCE ? _allianceNPC : _hordeNPC; } + inline Position const& GetPos() const { return _spawnPos; } + +private: + const uint32 _allianceNPC; + const uint32 _hordeNPC; + const Position _spawnPos; +}; + +const FactionSpawnerHelper executionerVictims[VictimCount] = +{ + { NPC_CAPTAIN_ALINA, NPC_CAPTAIN_BONESHATTER, { 138.8807f, -84.22707f, 1.992269f, 0.06981317f } }, + { NPC_ALLIANCE_VICTIM_1, NPC_HORDE_VICTIM_1, { 151.2411f, -91.02930f, 2.019741f, 1.57079600f } }, + { NPC_ALLIANCE_VICTIM_2, NPC_HORDE_VICTIM_2, { 151.0459f, -77.51981f, 2.021008f, 4.74729500f } } +}; + + #endif diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index f3c8396832c..87bd5923c8f 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -338,7 +338,7 @@ class spell_q11396_11399_scourging_crystal_controller : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_q11396_11399_scourging_crystal_controller_SpellScript(); - }; + } }; // 43882 Scourging Crystal Controller Dummy @@ -374,7 +374,7 @@ class spell_q11396_11399_scourging_crystal_controller_dummy : public SpellScript SpellScript* GetSpellScript() const override { return new spell_q11396_11399_scourging_crystal_controller_dummy_SpellScript(); - }; + } }; // http://www.wowhead.com/quest=11515 Blood for Blood @@ -855,7 +855,7 @@ class spell_symbol_of_life_dummy : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_symbol_of_life_dummy_SpellScript(); - }; + } }; // http://www.wowhead.com/quest=12659 Scalps! @@ -898,7 +898,7 @@ class spell_q12659_ahunaes_knife : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_q12659_ahunaes_knife_SpellScript(); - }; + } }; enum StoppingTheSpread @@ -944,7 +944,7 @@ class spell_q9874_liquid_fire : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_q9874_liquid_fire_SpellScript(); - }; + } }; enum SalvagingLifesStength @@ -988,7 +988,7 @@ class spell_q12805_lifeblood_dummy : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_q12805_lifeblood_dummy_SpellScript(); - }; + } }; /* diff --git a/src/server/shared/Common.h b/src/server/shared/Common.h index dc9e948966d..e83340bdd84 100644 --- a/src/server/shared/Common.h +++ b/src/server/shared/Common.h @@ -38,6 +38,7 @@ #include <queue> #include <sstream> #include <algorithm> +#include <memory> #include <boost/optional.hpp> #include <boost/utility/in_place_factory.hpp> @@ -164,4 +165,14 @@ struct LocalizedString template <typename T> using Optional = boost::optional<T>; +namespace Trinity +{ + //! std::make_unique implementation (TODO: remove this once C++14 is supported) + template<typename T, typename ...Args> + std::unique_ptr<T> make_unique(Args&& ...args) + { + return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); + } +} + #endif diff --git a/src/server/shared/Cryptography/SHA1.h b/src/server/shared/Cryptography/SHA1.h index ebd9f721d4a..f59bdc25556 100644 --- a/src/server/shared/Cryptography/SHA1.h +++ b/src/server/shared/Cryptography/SHA1.h @@ -39,8 +39,8 @@ class SHA1Hash void Initialize(); void Finalize(); - uint8 *GetDigest(void) { return mDigest; }; - int GetLength(void) const { return SHA_DIGEST_LENGTH; }; + uint8 *GetDigest(void) { return mDigest; } + int GetLength(void) const { return SHA_DIGEST_LENGTH; } private: SHA_CTX mC; diff --git a/src/server/shared/Cryptography/SHA256.h b/src/server/shared/Cryptography/SHA256.h index 659236f9495..1d85545b2e0 100644 --- a/src/server/shared/Cryptography/SHA256.h +++ b/src/server/shared/Cryptography/SHA256.h @@ -38,8 +38,8 @@ class SHA256Hash void Initialize(); void Finalize(); - uint8 *GetDigest(void) { return mDigest; }; - int GetLength(void) const { return SHA256_DIGEST_LENGTH; }; + uint8 *GetDigest(void) { return mDigest; } + int GetLength(void) const { return SHA256_DIGEST_LENGTH; } private: SHA256_CTX mC; diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index e9ce253d1cf..277ccd4569a 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -690,7 +690,12 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS, "SELECT buildingId FROM character_garrison_blueprints WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS, "INSERT INTO character_garrison_blueprints (guid, buildingId) VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS, "DELETE FROM character_garrison_blueprints WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, "SELECT plotInstanceId, buildingId, timeBuilt, active FROM character_garrison_buildings WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, "SELECT plotInstanceId, buildingId, timeBuilt, active FROM character_garrison_buildings WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS, "INSERT INTO character_garrison_buildings (guid, plotInstanceId, buildingId, timeBuilt, active) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS, "DELETE FROM character_garrison_buildings WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS, "SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS, "INSERT INTO character_garrison_followers (dbId, guid, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS, "DELETE gfab, gf FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE gf.guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "SELECT gfab.dbId, gfab.abilityId FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE guid = ? ORDER BY gfab.slot", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "INSERT INTO character_garrison_follower_abilities (dbId, abilityId, slot) VALUES (?, ?, ?)", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index 53c42a0b852..fc9c930e6b1 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -608,6 +608,11 @@ enum CharacterDatabaseStatements CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, CHAR_INS_CHARACTER_GARRISON_BUILDINGS, CHAR_DEL_CHARACTER_GARRISON_BUILDINGS, + CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS, + CHAR_INS_CHARACTER_GARRISON_FOLLOWERS, + CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS, + CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES, + CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES, MAX_CHARACTERDATABASE_STATEMENTS }; diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 70350f3136c..99d6cb7af50 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -46,7 +46,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_INS_IP_BANNED, "INSERT INTO ip_banned (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_IP_NOT_BANNED, "DELETE FROM ip_banned WHERE ip = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED, "UPDATE account_banned SET active = 0 WHERE id = ? AND active != 0", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED, "UPDATE account_banned SET unbandate = UNIX_TIMESTAMP(), active = 0 WHERE id = ? AND active != 0", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM, "DELETE FROM realmcharacters WHERE acctid = ? AND realmid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index f8f641a9ea7..e50cf42e439 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -61,6 +61,7 @@ HANDLE WheatyExceptionReport::m_hDumpFile; HANDLE WheatyExceptionReport::m_hProcess; SymbolPairs WheatyExceptionReport::symbols; std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails; +bool WheatyExceptionReport::stackOverflowException; // Declare global instance of class WheatyExceptionReport g_WheatyExceptionReport; @@ -72,6 +73,7 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor // Install the unhandled exception filter function m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter); m_hProcess = GetCurrentProcess(); + stackOverflowException = false; if (!IsDebuggerPresent()) { _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); @@ -97,6 +99,9 @@ WheatyExceptionReport::~WheatyExceptionReport() LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter( PEXCEPTION_POINTERS pExceptionInfo) { + if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) + stackOverflowException = true; + TCHAR module_folder_name[MAX_PATH]; GetModuleFileName(0, module_folder_name, MAX_PATH); TCHAR* pos = _tcsrchr(module_folder_name, '\\'); @@ -419,107 +424,114 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables) void WheatyExceptionReport::GenerateExceptionReport( PEXCEPTION_POINTERS pExceptionInfo) { - SYSTEMTIME systime; - GetLocalTime(&systime); - - // Start out with a banner - _tprintf(_T("Revision: %s\r\n"), _FULLVERSION); - _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); - PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; - - PrintSystemInfo(); - // First print information about the type of fault - _tprintf(_T("\r\n//=====================================================\r\n")); - _tprintf(_T("Exception code: %08X %s\r\n"), - pExceptionRecord->ExceptionCode, - GetExceptionString(pExceptionRecord->ExceptionCode)); - - // Now print information about where the fault occured - TCHAR szFaultingModule[MAX_PATH]; - DWORD section; - DWORD_PTR offset; - GetLogicalAddress(pExceptionRecord->ExceptionAddress, - szFaultingModule, - sizeof(szFaultingModule), - section, offset); + __try + { + SYSTEMTIME systime; + GetLocalTime(&systime); + + // Start out with a banner + _tprintf(_T("Revision: %s\r\n"), _FULLVERSION); + _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); + PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; + + PrintSystemInfo(); + // First print information about the type of fault + _tprintf(_T("\r\n//=====================================================\r\n")); + _tprintf(_T("Exception code: %08X %s\r\n"), + pExceptionRecord->ExceptionCode, + GetExceptionString(pExceptionRecord->ExceptionCode)); + + // Now print information about where the fault occured + TCHAR szFaultingModule[MAX_PATH]; + DWORD section; + DWORD_PTR offset; + GetLogicalAddress(pExceptionRecord->ExceptionAddress, + szFaultingModule, + sizeof(szFaultingModule), + section, offset); #ifdef _M_IX86 - _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), - pExceptionRecord->ExceptionAddress, - section, offset, szFaultingModule); + _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), + pExceptionRecord->ExceptionAddress, + section, offset, szFaultingModule); #endif #ifdef _M_X64 - _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), - pExceptionRecord->ExceptionAddress, - section, offset, szFaultingModule); + _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), + pExceptionRecord->ExceptionAddress, + section, offset, szFaultingModule); #endif - PCONTEXT pCtx = pExceptionInfo->ContextRecord; + PCONTEXT pCtx = pExceptionInfo->ContextRecord; - // Show the registers - #ifdef _M_IX86 // X86 Only! - _tprintf(_T("\r\nRegisters:\r\n")); + // Show the registers +#ifdef _M_IX86 // X86 Only! + _tprintf(_T("\r\nRegisters:\r\n")); - _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") - , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, - pCtx->Esi, pCtx->Edi); + _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") + , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, + pCtx->Esi, pCtx->Edi); - _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); - _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), - pCtx->SegSs, pCtx->Esp, pCtx->Ebp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), - pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); - _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); - #endif + _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); + _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), + pCtx->SegSs, pCtx->Esp, pCtx->Ebp); + _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); + _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); +#endif - #ifdef _M_X64 - _tprintf(_T("\r\nRegisters:\r\n")); - _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") - _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n") - , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, - pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15); - _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); - _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), - pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), - pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); - _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); - #endif +#ifdef _M_X64 + _tprintf(_T("\r\nRegisters:\r\n")); + _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") + _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n") + , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, + pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15); + _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); + _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), + pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); + _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); + _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); +#endif - SymSetOptions(SYMOPT_DEFERRED_LOADS); + SymSetOptions(SYMOPT_DEFERRED_LOADS); - // Initialize DbgHelp - if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) - { - _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), - ErrorMessage(GetLastError())); - } + // Initialize DbgHelp + if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) + { + _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), + ErrorMessage(GetLastError())); + } - CONTEXT trashableContext = *pCtx; + CONTEXT trashableContext = *pCtx; - WriteStackDetails(&trashableContext, false, NULL); - printTracesForAllThreads(false); + WriteStackDetails(&trashableContext, false, NULL); + printTracesForAllThreads(false); -// #ifdef _M_IX86 // X86 Only! + // #ifdef _M_IX86 // X86 Only! - _tprintf(_T("========================\r\n")); - _tprintf(_T("Local Variables And Parameters\r\n")); + _tprintf(_T("========================\r\n")); + _tprintf(_T("Local Variables And Parameters\r\n")); - trashableContext = *pCtx; - WriteStackDetails(&trashableContext, true, NULL); - printTracesForAllThreads(true); + trashableContext = *pCtx; + WriteStackDetails(&trashableContext, true, NULL); + printTracesForAllThreads(true); - /*_tprintf(_T("========================\r\n")); - _tprintf(_T("Global Variables\r\n")); + /*_tprintf(_T("========================\r\n")); + _tprintf(_T("Global Variables\r\n")); - SymEnumSymbols(GetCurrentProcess(), + SymEnumSymbols(GetCurrentProcess(), (UINT_PTR)GetModuleHandle(szFaultingModule), 0, EnumerateSymbolsCallback, 0);*/ - // #endif // X86 Only! + // #endif // X86 Only! - SymCleanup(GetCurrentProcess()); + SymCleanup(GetCurrentProcess()); - _tprintf(_T("\r\n")); + _tprintf(_T("\r\n")); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + _tprintf(_T("Error writing the crash log\r\n")); + } } //====================================================================== @@ -1313,16 +1325,43 @@ DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address) //============================================================================ int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) { - TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; int retValue; - DWORD cbWritten; va_list argptr; - va_start(argptr, format); + if (stackOverflowException) + { + retValue = heapprintf(format, argptr); + va_end(argptr); + } + else + { + retValue = stackprintf(format, argptr); + va_end(argptr); + } + + return retValue; +} + +int __cdecl WheatyExceptionReport::stackprintf(const TCHAR * format, va_list argptr) +{ + int retValue; + DWORD cbWritten; + + TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; retValue = vsprintf(szBuff, format, argptr); - va_end(argptr); + WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); + return retValue; +} + +int __cdecl WheatyExceptionReport::heapprintf(const TCHAR * format, va_list argptr) +{ + int retValue; + DWORD cbWritten; + TCHAR* szBuff = (TCHAR*)malloc(sizeof(TCHAR) * WER_LARGE_BUFFER_SIZE); + retValue = vsprintf(szBuff, format, argptr); WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); + free(szBuff); return retValue; } diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h index b7731daaa2b..101b6187f2b 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ b/src/server/shared/Debugging/WheatyExceptionReport.h @@ -178,6 +178,8 @@ class WheatyExceptionReport static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); static int __cdecl _tprintf(const TCHAR * format, ...); + static int __cdecl stackprintf(const TCHAR * format, va_list argptr); + static int __cdecl heapprintf(const TCHAR * format, va_list argptr); static bool StoreSymbol(DWORD type , DWORD_PTR offset); static void ClearSymbols(); @@ -191,6 +193,7 @@ class WheatyExceptionReport static HANDLE m_hProcess; static SymbolPairs symbols; static std::stack<SymbolDetail> symbolDetails; + static bool stackOverflowException; static char* PushSymbolDetail(char* pszCurrBuffer); static char* PopSymbolDetail(char* pszCurrBuffer); diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index e22a06e635e..5b3782fce55 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -23,6 +23,7 @@ #include "Appender.h" #include "Logger.h" #include "StringFormat.h" +#include "Common.h" #include <boost/asio/io_service.hpp> #include <boost/asio/strand.hpp> @@ -64,7 +65,7 @@ class Log template<typename... Args> inline void outMessage(std::string const& filter, LogLevel const level, const char* fmt, Args const&... args) { - write(std::unique_ptr<LogMessage>(new LogMessage(level, filter, Trinity::StringFormat(fmt, args...)))); + write(Trinity::make_unique<LogMessage>(level, filter, Trinity::StringFormat(fmt, args...))); } template<typename... Args> @@ -73,7 +74,7 @@ class Log if (!ShouldLog("commands.gm", LOG_LEVEL_INFO)) return; - std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...)))); + std::unique_ptr<LogMessage> msg = Trinity::make_unique<LogMessage>(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...))); msg->param1 = std::to_string(account); diff --git a/src/server/shared/PrecompiledHeaders/sharedPCH.h b/src/server/shared/PrecompiledHeaders/sharedPCH.h index d0c15b17f0c..87af9f44eb7 100644 --- a/src/server/shared/PrecompiledHeaders/sharedPCH.h +++ b/src/server/shared/PrecompiledHeaders/sharedPCH.h @@ -6,3 +6,4 @@ #include "SQLOperation.h" #include "Errors.h" #include "TypeList.h" +#include "TaskScheduler.h" diff --git a/src/server/shared/Updater/DBUpdater.cpp b/src/server/shared/Updater/DBUpdater.cpp index 9806151b4c4..10c8c163ec4 100644 --- a/src/server/shared/Updater/DBUpdater.cpp +++ b/src/server/shared/Updater/DBUpdater.cpp @@ -381,8 +381,27 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos args.push_back("-h" + host); args.push_back("-u" + user); args.push_back("-p" + password); + + // Check if we want to connect through ip or socket (Unix only) +#ifdef _WIN32 + args.push_back("-P" + port_or_socket); +#else + + if (!std::isdigit(port_or_socket[0])) + { + // We can't check here if host == "." because is named localhost if socket option is enabled + args.push_back("-P0"); + args.push_back("--protocol=SOCKET"); + args.push_back("-S" + port_or_socket); + } + else + // generic case + args.push_back("-P" + port_or_socket); + +#endif + // Set the default charset to utf8 args.push_back("--default-character-set=utf8"); diff --git a/src/server/shared/Utilities/TaskScheduler.cpp b/src/server/shared/Utilities/TaskScheduler.cpp new file mode 100644 index 00000000000..c945ad4dab0 --- /dev/null +++ b/src/server/shared/Utilities/TaskScheduler.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2008-2015 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 "TaskScheduler.h" + +TaskScheduler& TaskScheduler::Update() +{ + _now = clock_t::now(); + Dispatch(); + return *this; +} + +TaskScheduler& TaskScheduler::Update(size_t const milliseconds) +{ + return Update(std::chrono::milliseconds(milliseconds)); +} + +TaskScheduler& TaskScheduler::Async(std::function<void()> const& callable) +{ + _asyncHolder.push(callable); + return *this; +} + +TaskScheduler& TaskScheduler::CancelAll() +{ + /// Clear the task holder + _task_holder.Clear(); + _asyncHolder = AsyncHolder(); + return *this; +} + +TaskScheduler& TaskScheduler::CancelGroup(group_t const group) +{ + _task_holder.RemoveIf([group](TaskContainer const& task) -> bool + { + return task->IsInGroup(group); + }); + return *this; +} + +TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups) +{ + std::for_each(groups.begin(), groups.end(), + std::bind(&TaskScheduler::CancelGroup, this, std::placeholders::_1)); + + return *this; +} + +TaskScheduler& TaskScheduler::InsertTask(TaskContainer task) +{ + _task_holder.Push(std::forward<TaskContainer>(task)); + return *this; +} + +void TaskScheduler::Dispatch() +{ + // Process all asyncs + while (!_asyncHolder.empty()) + { + _asyncHolder.front()(); + _asyncHolder.pop(); + } + + while (!_task_holder.IsEmpty()) + { + if (_task_holder.First()->_end > _now) + break; + + // Perfect forward the context to the handler + // Use weak references to catch destruction before callbacks. + TaskContext context(new TaskContextInstance(_task_holder.Pop(), + std::weak_ptr<TaskScheduler>(self_reference))); + + // Invoke the context + context->Invoke(); + } +} + +void TaskScheduler::TaskQueue::Push(TaskContainer&& task) +{ + container.insert(task); +} + +auto TaskScheduler::TaskQueue::Pop() -> TaskContainer +{ + TaskContainer result = *container.begin(); + container.erase(container.begin()); + return result; +} + +auto TaskScheduler::TaskQueue::First() const -> TaskContainer const& +{ + return *container.begin(); +} + +void TaskScheduler::TaskQueue::Clear() +{ + container.clear(); +} + +void TaskScheduler::TaskQueue::RemoveIf(std::function<bool(TaskContainer const&)> const& filter) +{ + for (auto itr = container.begin(); itr != container.end();) + if (filter(*itr)) + itr = container.erase(itr); + else + ++itr; +} + +void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter) +{ + std::vector<TaskContainer> cache; + for (auto itr = container.begin(); itr != container.end();) + if (filter(*itr)) + { + cache.push_back(*itr); + itr = container.erase(itr); + } + else + ++itr; + + container.insert(cache.begin(), cache.end()); +} + +bool TaskScheduler::TaskQueue::IsEmpty() const +{ + return container.empty(); +} + +TaskContextInstance& TaskContextInstance::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply) +{ + if (auto const owner = _owner.lock()) + apply(*owner); + + return *this; +} + +bool TaskContextInstance::IsInGroup(TaskScheduler::group_t const group) const +{ + return _task->IsInGroup(group); +} + +TaskContextInstance& TaskContextInstance::SetGroup(TaskScheduler::group_t const group) +{ + _task->_group = group; + return *this; +} + +TaskContextInstance& TaskContextInstance::ClearGroup() +{ + _task->_group = boost::none; + return *this; +} + +TaskScheduler::repeated_t TaskContextInstance::GetRepeatCounter() const +{ + return _task->_repeated; +} + +TaskContextInstance& TaskContextInstance::Async(std::function<void()> const& callable) +{ + return Dispatch(std::bind(&TaskScheduler::Async, std::placeholders::_1, callable)); +} + +TaskContextInstance& TaskContextInstance::CancelAll() +{ + return Dispatch(std::mem_fn(&TaskScheduler::CancelAll)); +} + +TaskContextInstance& TaskContextInstance::CancelGroup(TaskScheduler::group_t const group) +{ + return Dispatch(std::bind(&TaskScheduler::CancelGroup, std::placeholders::_1, group)); +} + +TaskContextInstance& TaskContextInstance::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups) +{ + return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, groups)); +} + +void TaskContextInstance::AssertOnConsumed() +{ + // This was adapted to TC to prevent static analysis tools from complaining. + // If you encounter this assertion check if you repeat a TaskContext more then 1 time! + ASSERT(_task && "Bad task logic, task context was consumed already!"); +} + +void TaskContextInstance::Invoke() +{ + _task->_task(shared_from_this()); +} diff --git a/src/server/shared/Utilities/TaskScheduler.h b/src/server/shared/Utilities/TaskScheduler.h new file mode 100644 index 00000000000..3498a9bcf6c --- /dev/null +++ b/src/server/shared/Utilities/TaskScheduler.h @@ -0,0 +1,591 @@ +/* + * Copyright (C) 2008-2015 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 _TASK_SCHEDULER_H_ +#define _TASK_SCHEDULER_H_ + +#include <algorithm> +#include <chrono> +#include <vector> +#include <queue> +#include <memory> +#include <utility> +#include <set> + +#include <boost/optional.hpp> + +#include "Util.h" + +class TaskContextInstance; + +typedef std::shared_ptr<TaskContextInstance> TaskContext; + +/// The TaskScheduler class provides the ability to schedule std::function's in the near future. +/// Use TaskScheduler::Update to update the scheduler. +/// Popular methods are: +/// * Schedule (Schedules a std::function which will be executed in the near future). +/// * Schedules an asynchronous function which will be executed at the next update tick. +/// * Cancel, Delay & Reschedule (Methods to manipulate already scheduled tasks). +/// Tasks are organized in groups (uint), multiple tasks can have the same group id, +/// you can provide a group or not, but keep in mind that you can only manipulate specific tasks through its group id! +/// Tasks callbacks use the function signature void(TaskContext) where TaskContext provides +/// access to the function schedule plan which makes it possible to repeat the task +/// with the same duration or a new one. +/// It also provides access to the repeat counter which is useful for task that repeat itself often +/// but behave different every time (spoken event dialogs for example). +class TaskScheduler +{ + friend class TaskContextInstance; + + // Time definitions (use steady clock) + typedef std::chrono::steady_clock clock_t; + typedef clock_t::time_point timepoint_t; + typedef clock_t::duration duration_t; + + // Task group type + typedef uint32 group_t; + // Task repeated type + typedef uint32 repeated_t; + // Task handle type + typedef std::function<void(TaskContext)> task_handler_t; + + class Task + { + friend class TaskContextInstance; + friend class TaskScheduler; + + timepoint_t _end; + duration_t _duration; + boost::optional<group_t> _group; + repeated_t _repeated; + task_handler_t _task; + + public: + // All Argument construct + Task(timepoint_t const& end, duration_t const& duration, boost::optional<group_t> const& group, + repeated_t const repeated, task_handler_t const& task) + : _end(end), _duration(duration), _group(group), _repeated(repeated), _task(task) { } + + // Minimal Argument construct + Task(timepoint_t const& end, duration_t const& duration, task_handler_t const& task) + : _end(end), _duration(duration), _group(boost::none), _repeated(0), _task(task) { } + + // Copy construct + Task(Task const&) = delete; + // Move construct + Task(Task&&) = delete; + // Copy Assign + Task& operator= (Task const&) = default; + // Move Assign + Task& operator= (Task&& right) = delete; + + // Order tasks by its end + inline bool operator< (Task const& other) const + { + return _end < other._end; + } + + inline bool operator> (Task const& other) const + { + return _end > other._end; + } + + // Compare tasks with its end + inline bool operator== (Task const& other) + { + return _end == other._end; + } + + // Returns true if the task is in the given group + inline bool IsInGroup(group_t const group) const + { + return _group == group; + } + }; + + typedef std::shared_ptr<Task> TaskContainer; + + /// Container which provides Task order, insert and reschedule operations. + struct Compare + { + bool operator() (TaskContainer const& left, TaskContainer const& right) + { + return (*left.get()) < (*right.get()); + }; + }; + + class TaskQueue + { + std::multiset<TaskContainer, Compare> container; + + public: + // Pushes the task in the container + void Push(TaskContainer&& task); + + /// Pops the task out of the container + TaskContainer Pop(); + + TaskContainer const& First() const; + + void Clear(); + + void RemoveIf(std::function<bool(TaskContainer const&)> const& filter); + + void ModifyIf(std::function<bool(TaskContainer const&)> const& filter); + + bool IsEmpty() const; + }; + + /// Contains a self reference to track if this object was deleted or not. + std::shared_ptr<TaskScheduler> self_reference; + + /// The current time point (now) + timepoint_t _now; + + /// The Task Queue which contains all task objects. + TaskQueue _task_holder; + + typedef std::queue<std::function<void()>> AsyncHolder; + + /// Contains all asynchronous tasks which will be invoked at + /// the next update tick. + AsyncHolder _asyncHolder; + +public: + TaskScheduler() : self_reference(this, [](TaskScheduler const*) { }), + _now(clock_t::now()) { } + + TaskScheduler(TaskScheduler const&) = delete; + TaskScheduler(TaskScheduler&&) = delete; + TaskScheduler& operator= (TaskScheduler const&) = delete; + TaskScheduler& operator= (TaskScheduler&&) = delete; + + /// Update the scheduler to the current time. + TaskScheduler& Update(); + + /// Update the scheduler with a difftime in ms. + TaskScheduler& Update(size_t const milliseconds); + + /// Update the scheduler with a difftime. + template<class _Rep, class _Period> + TaskScheduler& Update(std::chrono::duration<_Rep, _Period> const& difftime) + { + _now += difftime; + Dispatch(); + return *this; + } + + /// Schedule an callable function that is executed at the next update tick. + /// Its safe to modify the TaskScheduler from within the callable. + TaskScheduler& Async(std::function<void()> const& callable); + + /// Schedule an event with a fixed rate. + /// Never call this from within a task context! Use TaskContext::Schedule instead! + template<class _Rep, class _Period> + TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time, + task_handler_t const& task) + { + return ScheduleAt(_now, time, task); + } + + /// Schedule an event with a fixed rate. + /// Never call this from within a task context! Use TaskContext::Schedule instead! + template<class _Rep, class _Period> + TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time, + group_t const group, task_handler_t const& task) + { + return ScheduleAt(_now, time, group, task); + } + + /// Schedule an event with a randomized rate between min and max rate. + /// Never call this from within a task context! Use TaskContext::Schedule instead! + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task) + { + return Schedule(RandomDurationBetween(min, max), task); + } + + /// Schedule an event with a fixed rate. + /// Never call this from within a task context! Use TaskContext::Schedule instead! + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max, group_t const group, + task_handler_t const& task) + { + return Schedule(RandomDurationBetween(min, max), group, task); + } + + /// Cancels all tasks. + /// Never call this from within a task context! Use TaskContext::CancelAll instead! + TaskScheduler& CancelAll(); + + /// Cancel all tasks of a single group. + /// Never call this from within a task context! Use TaskContext::CancelGroup instead! + TaskScheduler& CancelGroup(group_t const group); + + /// Cancels all groups in the given std::vector. + /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}" + TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups); + + /// Delays all tasks with the given duration. + template<class _Rep, class _Period> + TaskScheduler& DelayAll(std::chrono::duration<_Rep, _Period> const& duration) + { + _task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool + { + task->_end += duration; + return true; + }); + return *this; + } + + /// Delays all tasks with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return DelayAll(RandomDurationBetween(min, max)); + } + + /// Delays all tasks of a group with the given duration. + template<class _Rep, class _Period> + TaskScheduler& DelayGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + { + _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool + { + if (task->IsInGroup(group)) + { + task->_end += duration; + return true; + } + else + return false; + }); + return *this; + } + + /// Delays all tasks of a group with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& DelayGroup(group_t const group, + std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return DelayGroup(group, RandomDurationBetween(min, max)); + } + + /// Reschedule all tasks with a given duration. + template<class _Rep, class _Period> + TaskScheduler& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration) + { + auto const end = _now + duration; + _task_holder.ModifyIf([end](TaskContainer const& task) -> bool + { + task->_end = end; + return true; + }); + return *this; + } + + /// Reschedule all tasks with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return RescheduleAll(RandomDurationBetween(min, max)); + } + + /// Reschedule all tasks of a group with the given duration. + template<class _Rep, class _Period> + TaskScheduler& RescheduleGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + { + auto const end = _now + duration; + _task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool + { + if (task->IsInGroup(group)) + { + task->_end = end; + return true; + } + else + return false; + }); + return *this; + } + + /// Reschedule all tasks of a group with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& RescheduleGroup(group_t const group, + std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return RescheduleGroup(group, RandomDurationBetween(min, max)); + } + +private: + /// Insert a new task to the enqueued tasks. + TaskScheduler& InsertTask(TaskContainer task); + + template<class _Rep, class _Period> + TaskScheduler& ScheduleAt(timepoint_t const& end, + std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task) + { + return InsertTask(TaskContainer(new Task(end + time, time, task))); + } + + /// Schedule an event with a fixed rate. + /// Never call this from within a task context! Use TaskContext::schedule instead! + template<class _Rep, class _Period> + TaskScheduler& ScheduleAt(timepoint_t const& end, + std::chrono::duration<_Rep, _Period> const& time, + group_t const group, task_handler_t const& task) + { + static repeated_t const DEFAULT_REPEATED = 0; + return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, task))); + } + + // Returns a random duration between min and max + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + std::chrono::milliseconds + static RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + auto const milli_min = std::chrono::duration_cast<std::chrono::milliseconds>(min); + auto const milli_max = std::chrono::duration_cast<std::chrono::milliseconds>(max); + + // TC specific: use SFMT URandom + return std::chrono::milliseconds(urand(milli_min.count(), milli_max.count())); + } + + /// Dispatch remaining tasks + void Dispatch(); +}; + +class TaskContextInstance + : public std::enable_shared_from_this<TaskContextInstance> +{ + friend class TaskScheduler; + + /// Associated task + TaskScheduler::TaskContainer _task; + + /// Owner + std::weak_ptr<TaskScheduler> const _owner; + + /// Dispatches an action safe on the TaskScheduler + TaskContextInstance& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply); + +public: + explicit TaskContextInstance(TaskScheduler::TaskContainer task, std::weak_ptr<TaskScheduler>&& owner) + : _task(task), _owner(owner) { } + + /// Returns true if the event is in the given group + bool IsInGroup(TaskScheduler::group_t const group) const; + + /// Sets the event in the given group + TaskContextInstance& SetGroup(TaskScheduler::group_t const group); + + /// Removes the group from the event + TaskContextInstance& ClearGroup(); + + /// Returns the repeat counter which increases every time the task is repeated. + TaskScheduler::repeated_t GetRepeatCounter() const; + + /// Repeats the event and sets a new duration. + /// std::chrono::seconds(5) for example. + /// This will consume the task context, its not possible to repeat the task again + /// from the same task context! + template<class _Rep, class _Period> + TaskContextInstance& Repeat(std::chrono::duration<_Rep, _Period> const& duration) + { + AssertOnConsumed(); + + // Set new duration, in-context timing and increment repeat counter + _task->_duration = duration; + _task->_end += duration; + _task->_repeated += 1; + return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task)); + } + + /// Repeats the event with the same duration. + /// This will consume the task context, its not possible to repeat the task again + /// from the same task context! + TaskContextInstance& Repeat() + { + return Repeat(_task->_duration); + } + + /// Repeats the event and set a new duration that is randomized between min and max. + /// std::chrono::seconds(5) for example. + /// This will consume the task context, its not possible to repeat the task again + /// from the same task context! + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContextInstance& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return Repeat(TaskScheduler::RandomDurationBetween(min, max)); + } + + /// Schedule a callable function that is executed at the next update tick from within the context. + /// Its safe to modify the TaskScheduler from within the callable. + TaskContextInstance& Async(std::function<void()> const& callable); + + /// Schedule an event with a fixed rate from within the context. + /// Its possible that the new event is executed immediately! + /// Use TaskScheduler::Async to create a task + /// which will be called at the next update tick. + template<class _Rep, class _Period> + TaskContextInstance& Schedule(std::chrono::duration<_Rep, _Period> const& time, + TaskScheduler::task_handler_t const& task) + { + auto const end = _task->_end; + return Dispatch([end, time, task](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.ScheduleAt<_Rep, _Period>(end, time, task); + }); + } + + /// Schedule an event with a fixed rate from within the context. + /// Its possible that the new event is executed immediately! + /// Use TaskScheduler::Async to create a task + /// which will be called at the next update tick. + template<class _Rep, class _Period> + TaskContextInstance& Schedule(std::chrono::duration<_Rep, _Period> const& time, + TaskScheduler::group_t const group, TaskScheduler::task_handler_t const& task) + { + auto const end = _task->_end; + return Dispatch([end, time, group, task](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.ScheduleAt<_Rep, _Period>(end, time, group, task); + }); + } + + /// Schedule an event with a randomized rate between min and max rate from within the context. + /// Its possible that the new event is executed immediately! + /// Use TaskScheduler::Async to create a task + /// which will be called at the next update tick. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContextInstance& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task) + { + return Schedule(TaskScheduler::RandomDurationBetween(min, max), task); + } + + /// Schedule an event with a randomized rate between min and max rate from within the context. + /// Its possible that the new event is executed immediately! + /// Use TaskScheduler::Async to create a task + /// which will be called at the next update tick. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContextInstance& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group, + TaskScheduler::task_handler_t const& task) + { + return Schedule(TaskScheduler::RandomDurationBetween(min, max), group, task); + } + + /// Cancels all tasks from within the context. + TaskContextInstance& CancelAll(); + + /// Cancel all tasks of a single group from within the context. + TaskContextInstance& CancelGroup(TaskScheduler::group_t const group); + + /// Cancels all groups in the given std::vector from within the context. + /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}" + TaskContextInstance& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups); + + /// Delays all tasks with the given duration from within the context. + template<class _Rep, class _Period> + TaskContextInstance& DelayAll(std::chrono::duration<_Rep, _Period> const& duration) + { + return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, duration)); + } + + /// Delays all tasks with a random duration between min and max from within the context. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContextInstance& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return DelayAll(TaskScheduler::RandomDurationBetween(min, max)); + } + + /// Delays all tasks of a group with the given duration from within the context. + template<class _Rep, class _Period> + TaskContextInstance& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + { + return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, duration)); + } + + /// Delays all tasks of a group with a random duration between min and max from within the context. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContextInstance& DelayGroup(TaskScheduler::group_t const group, + std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return DelayGroup(group, TaskScheduler::RandomDurationBetween(min, max)); + } + + /// Reschedule all tasks with the given duration. + template<class _Rep, class _Period> + TaskContextInstance& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration) + { + return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, duration)); + } + + /// Reschedule all tasks with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContextInstance& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return RescheduleAll(TaskScheduler::RandomDurationBetween(min, max)); + } + + /// Reschedule all tasks of a group with the given duration. + template<class _Rep, class _Period> + TaskContextInstance& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + { + return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, duration)); + } + + /// Reschedule all tasks of a group with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContextInstance& RescheduleGroup(TaskScheduler::group_t const group, + std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return RescheduleGroup(group, TaskScheduler::RandomDurationBetween(min, max)); + } + +private: + void AssertOnConsumed(); + + /// Invokes the associated hook of the task. + void Invoke(); +}; + +/// Milliseconds shorthand typedef. +typedef std::chrono::milliseconds Milliseconds; + +/// Seconds shorthand typedef. +typedef std::chrono::seconds Seconds; + +/// Minutes shorthand typedef. +typedef std::chrono::minutes Minutes; + +/// Hours shorthand typedef. +typedef std::chrono::hours Hours; + +#endif /// _TASK_SCHEDULER_H_ diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index c59b845e454..668cec43aca 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1018,7 +1018,7 @@ OffhandCheckAtSpellUnlearn = 1 # ClientCacheVersion # Description: Client cache version for client cache data reset. Use any value different # from DB and not recently been used to trigger client side cache reset. -# Default: 0 - (Use DB value from world DB db_version.cache_id field) +# Default: 0 - (Use DB value from world DB version.cache_id field) ClientCacheVersion = 0 |
